b0b04cae8739551cd24ee5b045d62d5391d81b01
[jalview.git] / src / jalview / datamodel / Alignment.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.datamodel;\r
20 \r
21 import jalview.analysis.*;\r
22 \r
23 import jalview.util.*;\r
24 \r
25 import java.util.*;\r
26 \r
27 /** Data structure to hold and manipulate a multiple sequence alignment\r
28  */\r
29 public class Alignment implements AlignmentI\r
30 {\r
31     protected Alignment dataset;\r
32     protected Vector sequences;\r
33     protected Vector groups = new Vector();\r
34     protected Vector superGroup = new Vector();\r
35     protected char gapCharacter = '-';\r
36     protected int type = NUCLEOTIDE;\r
37     public static final int PROTEIN = 0;\r
38     public static final int NUCLEOTIDE = 1;\r
39 \r
40     /** DOCUMENT ME!! */\r
41     public AlignmentAnnotation[] annotations;\r
42 \r
43     HiddenSequences hiddenSequences = new HiddenSequences(this);\r
44 \r
45 \r
46     /** Make an alignment from an array of Sequences.\r
47      *\r
48      * @param sequences\r
49      */\r
50     public Alignment(SequenceI[] seqs)\r
51     {\r
52         int i=0;\r
53 \r
54         if( jalview.util.Comparison.isNucleotide(seqs))\r
55           type = NUCLEOTIDE;\r
56         else\r
57           type = PROTEIN;\r
58 \r
59         sequences = new Vector();\r
60 \r
61         for (i = 0; i < seqs.length; i++)\r
62         {\r
63             sequences.addElement(seqs[i]);\r
64 \r
65             if(seqs[i].getDatasetSequence()!=null\r
66             && seqs[i].getDatasetSequence().getAnnotation()!=null)\r
67             {\r
68 \r
69               for(int a=0; a<seqs[i].getDatasetSequence().getAnnotation().length; a++)\r
70               {\r
71                        this.addAnnotation(seqs[i].getDatasetSequence().getAnnotation()[a], seqs[i]);\r
72               }\r
73             }\r
74         }\r
75 \r
76         getWidth();\r
77     }\r
78 \r
79     /**\r
80      * DOCUMENT ME!\r
81      *\r
82      * @return DOCUMENT ME!\r
83      */\r
84     public Vector getSequences()\r
85     {\r
86         return sequences;\r
87     }\r
88 \r
89     /**\r
90      * DOCUMENT ME!\r
91      *\r
92      * @param i DOCUMENT ME!\r
93      *\r
94      * @return DOCUMENT ME!\r
95      */\r
96     public SequenceI getSequenceAt(int i)\r
97     {\r
98         if (i < sequences.size())\r
99         {\r
100             return (SequenceI) sequences.elementAt(i);\r
101         }\r
102 \r
103         return null;\r
104     }\r
105 \r
106     /** Adds a sequence to the alignment.  Recalculates maxLength and size.\r
107      *\r
108      * @param snew\r
109      */\r
110     public void addSequence(SequenceI snew)\r
111     {\r
112         sequences.addElement(snew);\r
113     }\r
114 \r
115     /**\r
116      * DOCUMENT ME!\r
117      *\r
118      * @param seq DOCUMENT ME!\r
119      */\r
120     public void addSequence(SequenceI[] seq)\r
121     {\r
122         for (int i = 0; i < seq.length; i++)\r
123         {\r
124             addSequence(seq[i]);\r
125         }\r
126     }\r
127 \r
128     /** Adds a sequence to the alignment.  Recalculates maxLength and size.\r
129      *\r
130      * @param snew\r
131      */\r
132     public void setSequenceAt(int i, SequenceI snew)\r
133     {\r
134         SequenceI oldseq = getSequenceAt(i);\r
135         deleteSequence(oldseq);\r
136 \r
137         sequences.setElementAt(snew, i);\r
138     }\r
139 \r
140     /**\r
141      * DOCUMENT ME!\r
142      *\r
143      * @return DOCUMENT ME!\r
144      */\r
145     public Vector getGroups()\r
146     {\r
147         return groups;\r
148     }\r
149 \r
150     /** Takes out columns consisting entirely of gaps (-,.," ")\r
151      */\r
152     public void removeGaps()\r
153     {\r
154         SequenceI current;\r
155         int iSize = getWidth();\r
156 \r
157         for (int i = 0; i < iSize; i++)\r
158         {\r
159             boolean delete = true;\r
160 \r
161             for (int j = 0; j < getHeight(); j++)\r
162             {\r
163                 current = getSequenceAt(j);\r
164 \r
165                 if (current.getLength() > i)\r
166                 {\r
167                     /* MC Should move this to a method somewhere */\r
168                     if (!jalview.util.Comparison.isGap(current.getCharAt(i)))\r
169                     {\r
170                         delete = false;\r
171                     }\r
172                 }\r
173             }\r
174 \r
175             if (delete)\r
176             {\r
177                 deleteColumns(i, i);\r
178                 iSize--;\r
179                 i--;\r
180             }\r
181         }\r
182     }\r
183 \r
184     /** Removes a range of columns (start to end inclusive).\r
185      *\r
186      * @param start Start column in the alignment\r
187      * @param end End column in the alignment\r
188      */\r
189     public void deleteColumns(int start, int end)\r
190     {\r
191         deleteColumns(0, getHeight() - 1, start, end);\r
192     }\r
193 \r
194     /**\r
195      * DOCUMENT ME!\r
196      *\r
197      * @param seq1 DOCUMENT ME!\r
198      * @param seq2 DOCUMENT ME!\r
199      * @param start DOCUMENT ME!\r
200      * @param end DOCUMENT ME!\r
201      */\r
202     public void deleteColumns(int seq1, int seq2, int start, int end)\r
203     {\r
204         for (int i = 0; i <= (end - start); i++)\r
205         {\r
206             for (int j = seq1; j <= seq2; j++)\r
207             {\r
208                 getSequenceAt(j).deleteCharAt(start);\r
209             }\r
210         }\r
211     }\r
212 \r
213     /**\r
214      * DOCUMENT ME!\r
215      *\r
216      * @param i DOCUMENT ME!\r
217      */\r
218     public void trimLeft(int i)\r
219     {\r
220         int j, jSize = getHeight();\r
221         for (j = 0; j < jSize; j++)\r
222         {\r
223             SequenceI s = getSequenceAt(j);\r
224             int newstart = s.findPosition(i);\r
225 \r
226             if(i>s.getLength())\r
227             {\r
228               sequences.removeElement(s);\r
229               j--;\r
230               jSize--;\r
231             }\r
232             else\r
233             {\r
234               s.setStart(newstart);\r
235               s.setSequence(s.getSequence().substring(i));\r
236             }\r
237         }\r
238     }\r
239 \r
240     /**\r
241      * DOCUMENT ME!\r
242      *\r
243      * @param i DOCUMENT ME!\r
244      */\r
245     public void trimRight(int i)\r
246     {\r
247         for (int j = 0; j < getHeight(); j++)\r
248         {\r
249             SequenceI s = getSequenceAt(j);\r
250             int newend = s.findPosition(i);\r
251 \r
252             s.setEnd(newend);\r
253             if(s.getLength()>i)\r
254               s.setSequence(s.getSequence().substring(0, i + 1));\r
255         }\r
256     }\r
257 \r
258     /**\r
259      * DOCUMENT ME!\r
260      *\r
261      * @param s DOCUMENT ME!\r
262      */\r
263     public void deleteSequence(SequenceI s)\r
264     {\r
265         for (int i = 0; i < getHeight(); i++)\r
266         {\r
267             if (getSequenceAt(i) == s)\r
268             {\r
269                 deleteSequence(i);\r
270             }\r
271         }\r
272     }\r
273 \r
274     /**\r
275      * DOCUMENT ME!\r
276      *\r
277      * @param i DOCUMENT ME!\r
278      */\r
279     public void deleteSequence(int i)\r
280     {\r
281         sequences.removeElementAt(i);\r
282     }\r
283 \r
284     /**\r
285      * DOCUMENT ME!\r
286      *\r
287      * @param threshold DOCUMENT ME!\r
288      * @param sel DOCUMENT ME!\r
289      *\r
290      * @return DOCUMENT ME!\r
291      */\r
292     public Vector removeRedundancy(float threshold, Vector sel)\r
293     {\r
294         Vector del = new Vector();\r
295 \r
296         for (int i = 1; i < sel.size(); i++)\r
297         {\r
298             for (int j = 0; j < i; j++)\r
299             {\r
300                 // Only do the comparison if either have not been deleted\r
301                 if (!del.contains((SequenceI) sel.elementAt(i)) ||\r
302                         !del.contains((SequenceI) sel.elementAt(j)))\r
303                 {\r
304                     // use PID instead of Comparison (which is really not pleasant)\r
305                     float pid = Comparison.PID((SequenceI) sel.elementAt(j),\r
306                             (SequenceI) sel.elementAt(i));\r
307 \r
308                     if (pid >= threshold)\r
309                     {\r
310                         // Delete the shortest one\r
311                         if (((SequenceI) sel.elementAt(j)).getSequence().length() > ((SequenceI) sel\r
312                                                                                          .elementAt(\r
313                                     i)).getSequence().length())\r
314                         {\r
315                             del.addElement(sel.elementAt(i));\r
316                         }\r
317                         else\r
318                         {\r
319                             del.addElement(sel.elementAt(i));\r
320                         }\r
321                     }\r
322                 }\r
323             }\r
324         }\r
325 \r
326         // Now delete the sequences\r
327         for (int i = 0; i < del.size(); i++)\r
328         {\r
329             deleteSequence((SequenceI) del.elementAt(i));\r
330         }\r
331 \r
332         return del;\r
333     }\r
334 \r
335     /**    */\r
336     public SequenceGroup findGroup(int i)\r
337     {\r
338         return findGroup(getSequenceAt(i));\r
339     }\r
340 \r
341     /**    */\r
342     public SequenceGroup findGroup(SequenceI s)\r
343     {\r
344         for (int i = 0; i < this.groups.size(); i++)\r
345         {\r
346             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\r
347 \r
348             if (sg.sequences.contains(s))\r
349             {\r
350                 return sg;\r
351             }\r
352         }\r
353 \r
354         return null;\r
355     }\r
356 \r
357     /**\r
358      * DOCUMENT ME!\r
359      *\r
360      * @param s DOCUMENT ME!\r
361      *\r
362      * @return DOCUMENT ME!\r
363      */\r
364     public SequenceGroup[] findAllGroups(SequenceI s)\r
365     {\r
366         Vector temp = new Vector();\r
367 \r
368         int gSize = groups.size();\r
369         for (int i = 0; i < gSize; i++)\r
370         {\r
371             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\r
372             if(sg==null || sg.sequences==null)\r
373             {\r
374               this.deleteGroup(sg);\r
375               gSize--;\r
376               continue;\r
377             }\r
378 \r
379             if (sg.sequences.contains(s))\r
380             {\r
381                 temp.addElement(sg);\r
382             }\r
383         }\r
384 \r
385         SequenceGroup[] ret = new SequenceGroup[temp.size()];\r
386 \r
387         for (int i = 0; i < temp.size(); i++)\r
388         {\r
389             ret[i] = (SequenceGroup) temp.elementAt(i);\r
390         }\r
391 \r
392         return ret;\r
393     }\r
394 \r
395 \r
396 \r
397     /**    */\r
398     public void addGroup(SequenceGroup sg)\r
399     {\r
400         if (!groups.contains(sg))\r
401         {\r
402             groups.addElement(sg);\r
403         }\r
404     }\r
405 \r
406     /**\r
407      * DOCUMENT ME!\r
408      */\r
409     public void deleteAllGroups()\r
410     {\r
411         groups.removeAllElements();\r
412         superGroup.removeAllElements();\r
413 \r
414         int i = 0;\r
415 \r
416         while (i < sequences.size())\r
417         {\r
418             SequenceI s = getSequenceAt(i);\r
419             s.setColor(java.awt.Color.white);\r
420             i++;\r
421         }\r
422     }\r
423 \r
424     /**    */\r
425     public void deleteGroup(SequenceGroup g)\r
426     {\r
427         if (groups.contains(g))\r
428         {\r
429             groups.removeElement(g);\r
430         }\r
431     }\r
432 \r
433     /**    */\r
434     public SequenceI findName(String name)\r
435     {\r
436         int i = 0;\r
437 \r
438         while (i < sequences.size())\r
439         {\r
440             if (getSequenceAt(i).getName().equals(name))\r
441             {\r
442                 return getSequenceAt(i);\r
443             }\r
444 \r
445             i++;\r
446         }\r
447 \r
448         return null;\r
449     }\r
450 \r
451 \r
452     /**    */\r
453     public int findIndex(SequenceI s)\r
454     {\r
455         int i = 0;\r
456 \r
457         while (i < sequences.size())\r
458         {\r
459             if (s == getSequenceAt(i))\r
460             {\r
461                 return i;\r
462             }\r
463 \r
464             i++;\r
465         }\r
466 \r
467         return -1;\r
468     }\r
469 \r
470     /**\r
471      * DOCUMENT ME!\r
472      *\r
473      * @return DOCUMENT ME!\r
474      */\r
475     public int getHeight()\r
476     {\r
477         return sequences.size();\r
478     }\r
479 \r
480     /**\r
481      * DOCUMENT ME!\r
482      *\r
483      * @return DOCUMENT ME!\r
484      */\r
485     public int getWidth()\r
486     {\r
487         int maxLength = -1;\r
488 \r
489         for (int i = 0; i < sequences.size(); i++)\r
490         {\r
491             if (getSequenceAt(i).getLength() > maxLength)\r
492             {\r
493                 maxLength = getSequenceAt(i).getLength();\r
494             }\r
495         }\r
496 \r
497         return maxLength;\r
498     }\r
499 \r
500     /**\r
501      * DOCUMENT ME!\r
502      *\r
503      * @return DOCUMENT ME!\r
504      */\r
505     public int getMaxIdLength()\r
506     {\r
507         int max = 0;\r
508         int i = 0;\r
509 \r
510         while (i < sequences.size())\r
511         {\r
512             SequenceI seq = getSequenceAt(i);\r
513             String tmp = seq.getName() + "/" + seq.getStart() + "-" +\r
514                 seq.getEnd();\r
515 \r
516             if (tmp.length() > max)\r
517             {\r
518                 max = tmp.length();\r
519             }\r
520 \r
521             i++;\r
522         }\r
523 \r
524         return max;\r
525     }\r
526 \r
527     /**\r
528      * DOCUMENT ME!\r
529      *\r
530      * @param gc DOCUMENT ME!\r
531      */\r
532     public void setGapCharacter(char gc)\r
533     {\r
534         gapCharacter = gc;\r
535 \r
536         for (int i = 0; i < sequences.size(); i++)\r
537         {\r
538             Sequence seq = (Sequence) sequences.elementAt(i);\r
539             seq.sequence = seq.sequence.replace('.', gc);\r
540             seq.sequence = seq.sequence.replace('-', gc);\r
541             seq.sequence = seq.sequence.replace(' ', gc);\r
542         }\r
543     }\r
544 \r
545     /**\r
546      * DOCUMENT ME!\r
547      *\r
548      * @return DOCUMENT ME!\r
549      */\r
550     public char getGapCharacter()\r
551     {\r
552         return gapCharacter;\r
553     }\r
554 \r
555     /**\r
556      * DOCUMENT ME!\r
557      *\r
558      * @return DOCUMENT ME!\r
559      */\r
560     public Vector getAAFrequency()\r
561     {\r
562         return AAFrequency.calculate(sequences, 0, getWidth());\r
563     }\r
564 \r
565     /**\r
566      * DOCUMENT ME!\r
567      *\r
568      * @return DOCUMENT ME!\r
569      */\r
570     public boolean isAligned()\r
571     {\r
572         int width = getWidth();\r
573 \r
574         for (int i = 0; i < sequences.size(); i++)\r
575         {\r
576             if (getSequenceAt(i).getLength() != width)\r
577             {\r
578                 return false;\r
579             }\r
580         }\r
581 \r
582         return true;\r
583     }\r
584 \r
585     /**\r
586      * DOCUMENT ME!\r
587      *\r
588      * @param aa DOCUMENT ME!\r
589      */\r
590     public void deleteAnnotation(AlignmentAnnotation aa)\r
591     {\r
592         int aSize = 1;\r
593 \r
594         if (annotations != null)\r
595         {\r
596             aSize = annotations.length;\r
597         }\r
598 \r
599         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize - 1];\r
600 \r
601         int tIndex = 0;\r
602 \r
603         for (int i = 0; i < aSize; i++)\r
604         {\r
605             if (annotations[i] == aa)\r
606             {\r
607                 continue;\r
608             }\r
609 \r
610             temp[tIndex] = annotations[i];\r
611             tIndex++;\r
612         }\r
613 \r
614         annotations = temp;\r
615     }\r
616 \r
617     /**\r
618      *\r
619      * @param aa AlignmentAnnotation\r
620      * @param seqRef The sequence to associate this annotation with\r
621      * @return The adjusted AlignmentAnnotation, with dataset sequence and annotation added\r
622      */\r
623     public AlignmentAnnotation addAnnotation(AlignmentAnnotation aa, SequenceI seqRef)\r
624     {\r
625       if(seqRef!=null)\r
626       {\r
627           //We can only add Annotations to the dataset sequences\r
628            if(seqRef.getDatasetSequence()==null)\r
629            {\r
630                   setDataset(null);\r
631             }\r
632 \r
633         AlignmentAnnotation []  old = seqRef.getDatasetSequence().getAnnotation();\r
634 \r
635         //First check if this is a new annotation or not. If it is new,\r
636         //we must add the annotation to the dataset\r
637         boolean newAnnotation = true;\r
638         if(seqRef.getDatasetSequence().getAnnotation()!=null)\r
639         {\r
640           for(int a=0; a<old.length; a++)\r
641           {\r
642             if(old[a] == aa)\r
643             {\r
644 \r
645               newAnnotation = false;\r
646               break;\r
647             }\r
648           }\r
649         }\r
650 \r
651         if(newAnnotation)\r
652          {\r
653            seqRef.getDatasetSequence().addAlignmentAnnotation(aa);\r
654          }\r
655 \r
656           AlignmentAnnotation copy = null;\r
657           if (aa.graph > 0)\r
658             copy = new AlignmentAnnotation(\r
659                 aa.label, aa.description, aa.annotations, aa.graphMin,\r
660                 aa.graphMax, aa.graph\r
661                 );\r
662           else\r
663             copy = new AlignmentAnnotation(\r
664                 aa.label, aa.description, aa.annotations\r
665                 );\r
666 \r
667          copy.datasetAnnotation = aa;\r
668 \r
669          addAnnotation(copy);\r
670 \r
671          copy.sequenceRef = seqRef;\r
672 \r
673          return copy;\r
674       }\r
675       else\r
676       {\r
677         addAnnotation(aa);\r
678         return aa;\r
679       }\r
680     }\r
681 \r
682     public void adjustSequenceAnnotations()\r
683     {\r
684       if(annotations!=null)\r
685       {\r
686         for (int a = 0; a < annotations.length; a++)\r
687         {\r
688           if (annotations[a].sequenceRef != null)\r
689           {\r
690             annotations[a].adjustForAlignment();\r
691           }\r
692         }\r
693       }\r
694     }\r
695 \r
696     /**\r
697      * DOCUMENT ME!\r
698      *\r
699      * @param aa DOCUMENT ME!\r
700      */\r
701     public void addAnnotation(AlignmentAnnotation aa)\r
702     {\r
703         int aSize = 1;\r
704         if (annotations != null)\r
705         {\r
706             aSize = annotations.length + 1;\r
707         }\r
708 \r
709         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];\r
710 \r
711         temp[aSize-1] = aa;\r
712 \r
713         int i = 0;\r
714 \r
715         if (aSize > 1)\r
716         {\r
717             for (i = 0; i < (aSize-1); i++)\r
718             {\r
719                 temp[i] = annotations[i];\r
720             }\r
721         }\r
722 \r
723         annotations = temp;\r
724     }\r
725 \r
726     public void setAnnotationIndex(AlignmentAnnotation aa, int index)\r
727     {\r
728       if(aa==null || annotations==null || annotations.length-1<index)\r
729         return;\r
730 \r
731       int aSize = annotations.length;\r
732       AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];\r
733 \r
734       temp[index] = aa;\r
735 \r
736       for (int i = 0; i < aSize; i++)\r
737       {\r
738         if(i==index)\r
739           continue;\r
740 \r
741         if(i<index)\r
742           temp[i] = annotations[i];\r
743         else\r
744           temp[i] = annotations[i-1];\r
745       }\r
746 \r
747         annotations = temp;\r
748     }\r
749 \r
750     /**\r
751      * DOCUMENT ME!\r
752      *\r
753      * @return DOCUMENT ME!\r
754      */\r
755     public AlignmentAnnotation[] getAlignmentAnnotation()\r
756     {\r
757         return annotations;\r
758     }\r
759 \r
760     public void setNucleotide(boolean b)\r
761     {\r
762       if(b)\r
763         type = NUCLEOTIDE;\r
764       else\r
765         type = PROTEIN;\r
766     }\r
767 \r
768     public boolean isNucleotide()\r
769     {\r
770       if(type==NUCLEOTIDE)\r
771         return true;\r
772       else\r
773         return false;\r
774     }\r
775 \r
776     public void setDataset(Alignment data)\r
777     {\r
778       if(dataset==null && data==null)\r
779       {\r
780         // Create a new dataset for this alignment.\r
781         // Can only be done once, if dataset is not null\r
782         // This will not be performed\r
783         Sequence[] seqs = new Sequence[getHeight()];\r
784         for (int i = 0; i < getHeight(); i++)\r
785         {\r
786 \r
787           seqs[i] = new Sequence(getSequenceAt(i).getName(),\r
788                                  AlignSeq.extractGaps(\r
789                                      jalview.util.Comparison.GapChars,\r
790                                      getSequenceAt(i).getSequence()\r
791                                  ),\r
792                                  getSequenceAt(i).getStart(),\r
793                                  getSequenceAt(i).getEnd());\r
794 \r
795           getSequenceAt(i).setDatasetSequence(seqs[i]);\r
796         }\r
797 \r
798         dataset = new Alignment(seqs);\r
799       }\r
800       else if(dataset==null && data!=null)\r
801       {\r
802         dataset = data;\r
803       }\r
804     }\r
805 \r
806     public Alignment getDataset()\r
807     {\r
808       return dataset;\r
809     }\r
810 \r
811     public boolean padGaps() {\r
812       boolean modified=false;\r
813 \r
814       //Remove excess gaps from the end of alignment\r
815       int maxLength = -1;\r
816 \r
817       SequenceI current;\r
818       for (int i = 0; i < sequences.size(); i++)\r
819       {\r
820         current = getSequenceAt(i);\r
821         for (int j = current.getLength(); j > maxLength; j--)\r
822         {\r
823           if (j > maxLength && !jalview.util.Comparison.isGap(\r
824               current.getCharAt(j)))\r
825           {\r
826             maxLength = j;\r
827             break;\r
828           }\r
829         }\r
830       }\r
831 \r
832       maxLength++;\r
833 \r
834       for (int i = 0; i < sequences.size();\r
835            i++)\r
836       {\r
837         current = getSequenceAt(i);\r
838 \r
839         if (current.getLength() < maxLength)\r
840         {\r
841           current.insertCharAt(maxLength - 1, gapCharacter);\r
842           modified=true;\r
843         }\r
844         else if(current.getLength() > maxLength)\r
845         {\r
846           current.deleteChars(maxLength, current.getLength());\r
847         }\r
848       }\r
849       return modified;\r
850     }\r
851 \r
852     public HiddenSequences getHiddenSequences()\r
853     {\r
854       return hiddenSequences;\r
855     }\r
856 \r
857 }\r