JAL-2629 tidy unit tests, constants etc
[jalview.git] / src / jalview / datamodel / HiddenMarkovModel.java
1 package jalview.datamodel;
2
3 import jalview.schemes.ResidueProperties;
4
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 /**
11  * Data structure which stores a hidden Markov model. Currently contains file
12  * properties as well, not sure whether these should be transferred to the
13  * HMMFile class
14  * 
15  * @author TZVanaalten
16  * 
17  */
18 public class HiddenMarkovModel
19 {
20   private static final double LOG2 = Math.log(2);
21
22   // Stores file properties. Do not directly access this field as it contains
23   // only string value - use the getter methods. For example, to find the length
24   // of theHMM, use getModelLength()to return an int value
25   Map<String, String> fileProperties = new HashMap<>();
26   
27   // contains all of the symbols used in this model. The index of each symbol
28   // represents its lookup value
29   List<Character> symbols = new ArrayList<>();
30
31   // contains information for each node in the model. The begin node is at index
32   // 0. Node 0 contains average emission probabilities for each symbol
33   List<HMMNode> nodes = new ArrayList<>();
34
35   // contains the HMM node for each alignment column, alignment columns start at
36   // index 0;
37   Map<Integer, Integer> nodeLookup = new HashMap<>();
38   
39   // contains the symbol index for each symbol
40   Map<Character, Integer> symbolIndexLookup = new HashMap<>();
41
42   final static String YES = "yes";
43
44   final static String NO = "no";
45   
46   // keys for file properties hashmap
47   private final String NAME = "NAME";
48
49   private final String ACCESSION_NUMBER = "ACC";
50
51   private final String DESCRIPTION = "DESC";
52
53   private final String LENGTH = "LENG";
54
55   private final String MAX_LENGTH = "MAXL";
56
57   private final String ALPHABET = "ALPH";
58
59   private final String DATE = "DATE";
60
61   private final String COMMAND_LOG = "COM";
62
63   private final String NUMBER_OF_SEQUENCES = "NSEQ";
64
65   private final String EFF_NUMBER_OF_SEQUENCES = "EFFN";
66
67   private final String CHECK_SUM = "CKSUM";
68
69   private final String GATHERING_THRESHOLDS = "GA";
70
71   private final String TRUSTED_CUTOFFS = "TC";
72
73   private final String NOISE_CUTOFFS = "NC";
74
75   private final String STATISTICS = "STATS";
76
77   private final String COMPO = "COMPO";
78   
79   private final String GATHERING_THRESHOLD = "GA";
80
81   private final String TRUSTED_CUTOFF = "TC";
82
83   private final String NOISE_CUTOFF = "NC";
84
85   private final String VITERBI = "VITERBI";
86
87   private final String MSV = "MSV";
88
89   private final String FORWARD = "FORWARD";
90
91   private final String MAP = "MAP";
92
93   private final String REFERENCE_ANNOTATION = "RF";
94
95   private final String CONSENSUS_RESIDUE = "CONS";
96
97   private final String CONSENSUS_STRUCTURE = "CS";
98
99   private final String MASKED_VALUE = "MM";
100   
101   public static final int MATCHTOMATCH = 0;
102
103   public static final int MATCHTOINSERT = 1;
104
105   public static final int MATCHTODELETE = 2;
106
107   public static final int INSERTTOMATCH = 3;
108
109   public static final int INSERTTOINSERT = 4;
110
111   public static final int DELETETOMATCH = 5;
112
113   public static final int DELETETODELETE = 6;
114
115   String fileHeader;
116
117   /**
118    * Constructor
119    */
120   public HiddenMarkovModel()
121   {
122   }
123
124   public HiddenMarkovModel(HiddenMarkovModel hmm)
125   {
126     super();
127     this.fileProperties = new HashMap<>(hmm.fileProperties);
128     this.symbols = new ArrayList<>(hmm.symbols);
129     this.nodes = new ArrayList<>(hmm.nodes);
130     this.nodeLookup = new HashMap<>(hmm.nodeLookup);
131     this.symbolIndexLookup = new HashMap<>(
132             hmm.symbolIndexLookup);
133     this.fileHeader = new String(hmm.fileHeader);
134   }
135
136   /**
137    * Returns the information content at a specified column, calculated as the
138    * sum (over possible symbols) of the log ratio
139    * 
140    * <pre>
141    *  log(emission probability / background probability) / log(2)
142    * </pre>
143    * 
144    * @param column
145    *          column position (base 0)
146    * @return
147    */
148   public float getInformationContent(int column)
149   {
150     float informationContent = 0f;
151
152     for (char symbol : getSymbols())
153     {
154       float freq = ResidueProperties.backgroundFrequencies
155               .get(getAlphabetType()).get(symbol);
156       float prob = (float) getMatchEmissionProbability(column, symbol);
157       informationContent += prob * Math.log(prob / freq);
158     }
159
160     informationContent = informationContent / (float) LOG2;
161
162     return informationContent;
163   }
164
165   /**
166    * Gets the file header of the .hmm file this model came from
167    * 
168    * @return
169    */
170   public String getFileHeader()
171   {
172     return fileHeader;
173   }
174
175   /**
176    * Sets the file header of this model.
177    * 
178    * @param header
179    */
180   public void setFileHeader(String header)
181   {
182     fileHeader = header;
183   }
184
185   /**
186    * Returns the map containing the matches between nodes and alignment column
187    * indexes.
188    * 
189    * @return
190    * 
191    */
192   public Map<Integer, Integer> getNodeLookup()
193   {
194     return nodeLookup;
195   }
196
197   /**
198    * Returns the list of symbols used in this hidden Markov model.
199    * 
200    * @return
201    */
202   public List<Character> getSymbols()
203   {
204     return symbols;
205   }
206   
207   /**
208    * Returns the file properties.
209    * 
210    * @return
211    */
212   public Map<String, String> getFileProperties()
213   {
214     return fileProperties;
215   }
216
217   /**
218    * Gets the node in the hidden Markov model at the specified position.
219    * 
220    * @param nodeIndex
221    *          The index of the node requested. Node 0 optionally contains the
222    *          average match emission probabilities across the entire model, and
223    *          always contains the insert emission probabilities and state
224    *          transition probabilities for the begin node. Node 1 contains the
225    *          first node in the HMM that can correspond to a column in the
226    *          alignment.
227    * @return
228    */
229   public HMMNode getNode(int nodeIndex)
230   {
231     return getNodes().get(nodeIndex);
232   }
233
234   /**
235    * Sets the list of symbols used in the hidden Markov model to the list
236    * specified.
237    * 
238    * @param symbolsL
239    *          The list of symbols to which the current list is to be changed.
240    * 
241    */
242   public void setSymbols(List<Character> symbolsL)
243   {
244     this.symbols = symbolsL;
245   }
246
247   /**
248    * Returns the name of the sequence alignment on which the HMM is based.
249    * 
250    * @return
251    */
252   public String getName()
253   {
254     return fileProperties.get(NAME);
255   }
256   
257   /**
258    * Returns the accession number.
259    * @return
260    */
261   public String getAccessionNumber()
262   {
263     return fileProperties.get(ACCESSION_NUMBER);
264   }
265
266   /**
267    * Returns a description of the sequence alignment on which the hidden Markov
268    * model is based.
269    * 
270    * @return
271    */
272   public String getDescription()
273   {
274     return fileProperties.get(DESCRIPTION);
275   }
276
277   /**
278    * Returns the length of the hidden Markov model.
279    * 
280    * @return
281    */
282   public Integer getLength()
283   {
284     if (fileProperties.get(LENGTH) == null)
285     {
286       return null;
287     }
288     return Integer.parseInt(fileProperties.get(LENGTH));
289   }
290
291   /**
292    * Returns the max instance length within the hidden Markov model.
293    * 
294    * @return
295    */
296   public Integer getMaxInstanceLength()
297   {
298     if (fileProperties.get(MAX_LENGTH) == null)
299     {
300       return null;
301     }
302     return Integer.parseInt(fileProperties.get(MAX_LENGTH));
303   }
304
305   /**
306    * Returns the type of symbol alphabet - "amino", "DNA", "RNA" are the
307    * options. Other alphabets may be added.
308    * 
309    * @return
310    */
311   public String getAlphabetType()
312   {
313     return fileProperties.get(ALPHABET);
314   }
315
316   /**
317    * Returns the date as a String.
318    * 
319    * @return
320    */
321   public String getDate()
322   {
323     return fileProperties.get(DATE);
324   }
325
326   /**
327    * Returns the command line log.
328    * 
329    * @return
330    */
331   public String getCommandLineLog()
332   {
333     return fileProperties.get(COMMAND_LOG);
334   }
335
336   /**
337    * Returns the number of sequences on which the HMM was trained.
338    * 
339    * @return
340    */
341   public Integer getNumberOfSequences()
342   {
343     if (fileProperties.get(NUMBER_OF_SEQUENCES) == null)
344     {
345       return null;
346     }
347     return Integer.parseInt(fileProperties.get(NUMBER_OF_SEQUENCES));
348   }
349
350   /**
351    * Returns the effective number of sequences on which the HMM was based.
352    * 
353    * @param value
354    */
355   public Double getEffectiveNumberOfSequences()
356   {
357     if (fileProperties.get(LENGTH) == null)
358     {
359       return null;
360     }
361     return Double.parseDouble(fileProperties.get(EFF_NUMBER_OF_SEQUENCES));
362   }
363
364   /**
365    * Returns the checksum.
366    * 
367    * @return
368    */
369   public Long getCheckSum()
370   {
371     if (fileProperties.get(LENGTH) == null)
372     {
373       return null;
374     }
375     return Long.parseLong(fileProperties.get(CHECK_SUM));
376   }
377
378   /**
379    * Returns the list of nodes in this HMM.
380    * 
381    * @return
382    */
383   public List<HMMNode> getNodes()
384   {
385     return nodes;
386   }
387
388   /**
389    * Sets the list of nodes in this HMM to the given list.
390    * 
391    * @param nodes
392    *          The list of nodes to which the current list of nodes is being
393    *          changed.
394    */
395   public void setNodes(List<HMMNode> nodes)
396   {
397     this.nodes = nodes;
398   }
399   
400   /**
401    * Gets the match emission probability for a given symbol at a column in the
402    * alignment.
403    * 
404    * @param alignColumn
405    *          The index of the alignment column, starting at index 0. Index 0
406    *          usually corresponds to index 1 in the HMM.
407    * @param symbol
408    *          The symbol for which the desired probability is being requested.
409    * @return
410    * 
411    */
412   public double getMatchEmissionProbability(int alignColumn, char symbol)
413   {
414     int symbolIndex;
415     int nodeIndex;
416     double probability;
417     if (!symbolIndexLookup.containsKey(symbol))
418     {
419       return 0d;
420     }
421     symbolIndex = symbolIndexLookup.get(symbol);
422     if (nodeLookup.containsKey(alignColumn))
423     {
424       nodeIndex = nodeLookup.get(alignColumn);
425       probability = getNode(nodeIndex).getMatchEmissions().get(symbolIndex);
426       return probability;
427     }
428     else
429     {
430       return 0d;
431     }
432   }
433
434   /**
435    * Gets the insert emission probability for a given symbol at a column in the
436    * alignment.
437    * 
438    * @param alignColumn
439    *          The index of the alignment column, starting at index 0. Index 0
440    *          usually corresponds to index 1 in the HMM.
441    * @param symbol
442    *          The symbol for which the desired probability is being requested.
443    * @return
444    * 
445    */
446   public double getInsertEmissionProbability(int alignColumn, char symbol)
447   {
448     int symbolIndex;
449     int nodeIndex;
450     double probability;
451     if (!symbolIndexLookup.containsKey(symbol))
452     {
453       return 0d;
454     }
455     symbolIndex = symbolIndexLookup.get(symbol);
456     if (nodeLookup.containsKey(alignColumn))
457     {
458       nodeIndex = nodeLookup.get(alignColumn);
459       probability = getNode(nodeIndex).getInsertEmissions()
460               .get(symbolIndex);
461       return probability;
462     }
463     else
464     {
465       return 0d;
466     }
467
468   }
469   
470   /**
471    * Gets the state transition probability for a given symbol at a column in the
472    * alignment.
473    * 
474    * @param alignColumn
475    *          The index of the alignment column, starting at index 0. Index 0
476    *          usually corresponds to index 1 in the HMM.
477    * @param symbol
478    *          The symbol for which the desired probability is being requested.
479    * @return
480    * 
481    */
482   public Double getStateTransitionProbability(int alignColumn,
483           int transition)
484   {
485     int nodeIndex;
486     Double probability;
487     if (nodeLookup.containsKey(alignColumn))
488     {
489       nodeIndex = nodeLookup.get(alignColumn);
490       probability = getNode(nodeIndex).getStateTransitions()
491               .get(transition);
492       return probability;
493     }
494     else
495     {
496       return 0d;
497     }
498
499   }
500   
501   /**
502    * Returns the alignment column linked to the node at the given index.
503    * 
504    * @param nodeIndex
505    *          The index of the node, starting from index 1. Index 0 is the begin
506    *          node, which does not correspond to a column in the alignment.
507    * @return
508    */
509   public Integer getNodeAlignmentColumn(int nodeIndex)
510   {
511     Integer value = nodes.get(nodeIndex).getAlignmentColumn();
512     return value;
513   }
514   
515   /**
516    * Returns the consensus residue at the specified node.
517    * 
518    * @param nodeIndex
519    *          The index of the specified node.
520    * @return
521    */
522   public char getConsensusResidue(int nodeIndex)
523   {
524    char value = nodes.get(nodeIndex).getConsensusResidue();
525    return value;
526   }
527   
528   /**
529    * Returns the consensus at a given alignment column. If the character is
530    * lower case, its emission probability is less than 0.5.
531    * 
532    * @param columnIndex
533    *          The index of the column in the alignment for which the consensus
534    *          is desired. The list of columns starts at index 0.
535    * @return
536    */
537   public char getConsensusAtAlignColumn(int columnIndex)
538   {
539     char mostLikely = '-';
540     if (consensusResidueIsActive())
541     {
542
543     Integer index = findNodeIndex(columnIndex);
544     if (index == null)
545     {
546       return '-';
547     }
548       mostLikely = getNodes().get(index).getConsensusResidue();
549       return mostLikely;
550     }
551     else
552     {
553       double highestProb = 0;
554       for (char character : symbols)
555       {
556         Double prob = getMatchEmissionProbability(columnIndex, character);
557         if (prob > highestProb)
558         {
559           highestProb = prob;
560           mostLikely = character;
561         }
562       }
563       if (highestProb < 0.5)
564       {
565         mostLikely = Character.toLowerCase(mostLikely);
566       }
567       return mostLikely;
568     }
569
570   }
571
572   /**
573    * Returns the reference annotation at the specified node.
574    * 
575    * @param nodeIndex
576    *          The index of the specified node.
577    * @return
578    */
579   public char getReferenceAnnotation(int nodeIndex)
580   {
581    char value = nodes.get(nodeIndex).getReferenceAnnotation();
582    return value;
583   }
584   
585   /**
586    * Returns the mask value at the specified node.
587    * 
588    * @param nodeIndex
589    *          The index of the specified node.
590    * @return
591    */
592   public char getMaskedValue(int nodeIndex)
593   {
594    char value = nodes.get(nodeIndex).getMaskValue();
595    return value;
596   }
597   
598   /**
599    * Returns the consensus structure at the specified node.
600    * 
601    * @param nodeIndex
602    *          The index of the specified node.
603    * @return
604    */
605   public char getConsensusStructure(int nodeIndex)
606   {
607    char value = nodes.get(nodeIndex).getConsensusStructure();
608    return value;
609   }
610   
611   /**
612    * Returns the average match emission probability for a given symbol
613    * 
614    * @param symbolIndex
615    *          The index of the symbol.
616    * @return
617    * 
618    */
619   public double getAverageMatchEmission(int symbolIndex)
620   {
621     double value = nodes.get(0).getMatchEmissions().get(symbolIndex);
622     return value;
623   }
624
625   /**
626    * Returns the number of symbols in the alphabet used in this HMM.
627    * 
628    * @return
629    */
630   public int getNumberOfSymbols()
631   {
632     return symbols.size();
633   }
634
635   /**
636    * Adds a file property.
637    * 
638    * @param key
639    * @param value
640    */
641   public void addFileProperty(String key, String value)
642   {
643     fileProperties.put(key, value);
644   }
645
646   /**
647    * Returns a boolean indicating whether the reference annotation is active.
648    * 
649    * @return
650    */
651   public boolean referenceAnnotationIsActive()
652   {
653     String status;
654     status = fileProperties.get(REFERENCE_ANNOTATION);
655     if (status == null)
656     {
657       return false;
658     }
659     switch (status)
660     {
661     case YES:
662       return true;
663     case NO:
664       return false;
665     default:
666       return false;
667     }
668
669   }
670
671   /**
672    * Returns a boolean indicating whether the mask value annotation is active.
673    * 
674    * @return
675    */
676   public boolean maskValueIsActive()
677   {
678     String status;
679     status = fileProperties.get(MASKED_VALUE);
680     if (status == null)
681     {
682       return false;
683     }
684     switch (status)
685     {
686     case YES:
687       return true;
688     case NO:
689       return false;
690     default:
691       return false;
692     }
693
694   }
695
696   /**
697    * Returns a boolean indicating whether the consensus residue annotation is
698    * active.
699    * 
700    * @return
701    */
702   public boolean consensusResidueIsActive()
703   {
704     String status;
705     status = fileProperties.get(CONSENSUS_RESIDUE);
706     if (status == null)
707     {
708       return false;
709     }
710     switch (status)
711     {
712     case YES:
713       return true;
714     case NO:
715       return false;
716     default:
717       return false;
718     }
719
720   }
721
722   /**
723    * Returns a boolean indicating whether the consensus structure annotation is
724    * active.
725    * 
726    * @return
727    */
728   public boolean consensusStructureIsActive()
729   {
730     String status;
731     status = fileProperties.get(CONSENSUS_STRUCTURE);
732     if (status == null)
733     {
734       return false;
735     }
736     switch (status)
737     {
738     case YES:
739       return true;
740     case NO:
741       return false;
742     default:
743       return false;
744     }
745
746   }
747
748   /**
749    * Returns a boolean indicating whether the MAP annotation is active.
750    * 
751    * @return
752    */
753   public boolean mapIsActive()
754   {
755     String status;
756     status = fileProperties.get(MAP);
757     if (status == null)
758     {
759       return false;
760     }
761     switch (status)
762     {
763     case YES:
764       return true;
765     case NO:
766       return false;
767     default:
768       return false;
769     }
770
771   }
772
773   /**
774    * Sets the alignment column of the specified node.
775    * 
776    * @param nodeIndex
777    * 
778    * @param column
779    * 
780    */
781   public void setAlignmentColumn(int nodeIndex, int column)
782   {
783     nodes.get(nodeIndex).setAlignmentColumn(column);
784     nodeLookup.put(column, nodeIndex);
785   }
786
787   /**
788    * Clears all data in the node lookup map
789    */
790   public void emptyNodeLookup()
791   {
792     nodeLookup = new HashMap<>();
793   }
794
795
796   /**
797    * Sets the reference annotation at a given node.
798    * 
799    * @param nodeIndex
800    * @param value
801    */
802   public void setReferenceAnnotation(int nodeIndex, char value)
803   {
804     nodes.get(nodeIndex).setReferenceAnnotation(value);
805   }
806
807   /**
808    * Sets the consensus residue at a given node.
809    * 
810    * @param nodeIndex
811    * @param value
812    */
813   public void setConsensusResidue(int nodeIndex, char value)
814   {
815     nodes.get(nodeIndex).setConsensusResidue(value);
816   }
817
818   /**
819    * Sets the consensus structure at a given node.
820    * 
821    * @param nodeIndex
822    * @param value
823    */
824   public void setConsensusStructure(int nodeIndex, char value)
825   {
826     nodes.get(nodeIndex).setConsensusStructure(value);
827   }
828
829   /**
830    * Sets the mask value at a given node.
831    * 
832    * @param nodeIndex
833    * @param value
834    */
835   public void setMaskValue(int nodeIndex, char value)
836   {
837     nodes.get(nodeIndex).setMaskValue(value);
838   }
839
840   /**
841    * Temporary implementation, should not be used.
842    * 
843    * @return
844    */
845   public String getGatheringThreshold()
846   {
847     String value;
848     value = fileProperties.get("GA");
849     return value;
850   }
851
852   /**
853    * Temporary implementation, should not be used.
854    * 
855    * @return
856    */
857   public String getNoiseCutoff()
858   {
859     String value;
860     value = fileProperties.get("NC");
861     return value;
862   }
863
864   /**
865    * Temporary implementation, should not be used.
866    * 
867    * @return
868    */
869   public String getTrustedCutoff()
870   {
871     String value;
872     value = fileProperties.get("TC");
873     return value;
874   }
875
876   /**
877    * Temporary implementation, should not be used.
878    * 
879    * @return
880    */
881   public String getViterbi()
882   {
883     String value;
884     value = fileProperties.get(VITERBI);
885     return value;
886   }
887
888   /**
889    * Temporary implementation, should not be used.
890    * 
891    * @return
892    */
893   public String getMSV()
894   {
895     String value;
896     value = fileProperties.get(MSV);
897     return value;
898   }
899
900   /**
901    * Temporary implementation, should not be used.
902    * 
903    * @return
904    */
905   public String getForward()
906   {
907     String value;
908     value = fileProperties.get(FORWARD);
909     return value;
910   }
911
912   /**
913    * Sets the activation status of the MAP annotation.
914    * 
915    * @param status
916    */
917   public void setMAPStatus(boolean status)
918   {
919     fileProperties.put(MAP, status ? YES : NO);
920   }
921
922   /**
923    * Sets the activation status of the reference annotation.
924    * 
925    * @param status
926    */
927   public void setReferenceAnnotationStatus(boolean status)
928   {
929     fileProperties.put(REFERENCE_ANNOTATION, status ? YES : NO);
930   }
931
932   /**
933    * Sets the activation status of the mask value annotation.
934    * 
935    * @param status
936    */
937   public void setMaskedValueStatus(boolean status)
938   {
939     fileProperties.put(MASKED_VALUE, status ? YES : NO);
940   }
941
942   /**
943    * Sets the activation status of the consensus residue annotation.
944    * 
945    * @param status
946    */
947   public void setConsensusResidueStatus(boolean status)
948   {
949     fileProperties.put(CONSENSUS_RESIDUE, status ? YES : NO);
950   }
951
952   /**
953    * Sets the activation status of the consensus structure annotation.
954    * 
955    * @param status
956    */
957   public void setConsensusStructureStatus(boolean status)
958   {
959     fileProperties.put(CONSENSUS_STRUCTURE, status ? YES : NO);
960   }
961
962   /**
963    * Finds the index of the node in a hidden Markov model based on the column in
964    * the alignment
965    * 
966    * @param alignmentColumn
967    *          The index of the column in the alignment, with the indexes
968    *          starting from 0.
969    */
970
971   public Integer findNodeIndex(int alignmentColumn)
972   {
973     Integer index;
974     index = nodeLookup.get(alignmentColumn);
975     return index;
976   }
977
978   /**
979    * Finds the String values of a boolean. "yes" for true and "no" for false.
980    * 
981    * @param value
982    * @return
983    */
984   public static String findStringFromBoolean(boolean value)
985   {
986     if (value)
987     {
988       return YES;
989     }
990     else
991     {
992       return NO;
993     }
994   }
995
996
997
998   /**
999    * Returns the consensus sequence based on the most probable symbol at each
1000    * position. The sequence is adjusted to match the length of the existing
1001    * sequence alignment. Gap characters are used as padding.
1002    * 
1003    * @param length
1004    *          The length of the longest sequence in the existing alignment.
1005    * @return
1006    */
1007   public Sequence getConsensusSequence()
1008   {
1009     int start;
1010     int end;
1011     int modelLength;
1012     start = getNodeAlignmentColumn(1);
1013     modelLength = getLength();
1014     end = getNodeAlignmentColumn(modelLength);
1015     char[] sequence = new char[end + 1];
1016     for (int index = 0; index < end + 1; index++)
1017     {
1018       Character character;
1019
1020         character = getConsensusAtAlignColumn(index);
1021
1022       if (character == null || character == '-')
1023       {
1024         sequence[index] = '-';
1025       }
1026       else
1027       {
1028         sequence[index] = Character.toUpperCase(character);
1029       }
1030       }
1031
1032
1033     Sequence seq = new Sequence(getName(), sequence, start,
1034             end);
1035     return seq;
1036   }
1037
1038
1039   /**
1040    * Initiates a HMM consensus sequence
1041    * 
1042    * @return A new HMM consensus sequence
1043    */
1044   public SequenceI initHMMSequence()
1045   {
1046     Sequence consensus = getConsensusSequence();
1047     consensus.setIsHMMConsensusSequence(true);
1048     consensus.setHMM(this);
1049     return consensus;
1050   }
1051
1052   public int getSymbolIndex(char c)
1053   {
1054     return symbolIndexLookup.get(c);
1055   }
1056
1057   public void setSymbolIndex(Character c, Integer i)
1058   {
1059     symbolIndexLookup.put(c, i);
1060   }
1061
1062
1063 }
1064