fully integrate HMMER3 file format into Jalview
[jalview.git] / src / jalview / datamodel / HiddenMarkovModel.java
1 package jalview.datamodel;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Scanner;
8
9 /**
10  * Data structure which stores a hidden Markov model. Currently contains file properties as well, not sure whether these should be transferred to the HMMFile class
11  * 
12  * @author TZVanaalten
13  * 
14  */
15 public class HiddenMarkovModel
16 {
17   // Stores file properties. Do not directly access this field as it contains
18   // only string value - use the getter methods. For example, to find the length
19   // of theHMM, use getModelLength()to return an int value
20   Map<String, String> fileProperties = new HashMap<>();
21   
22   //contains all of the symbols used in this model. The index of each symbol represents its lookup value 
23   List<Character> symbols = new ArrayList<>();
24
25   // contains information for each node in the model. The begin node is at index
26   // 0. Node 0 contains average emission probabilities for each symbol
27   List<HMMNode> nodes = new ArrayList<>();
28
29   // contains the HMM node for each alignment column
30   Map<Integer, Integer> nodeLookup = new HashMap<>();
31   
32   //contains the symbol index for each symbol
33   Map<Character, Integer> symbolIndexLookup = new HashMap<>();
34
35
36   final static String YES = "yes";
37
38   final static String NO = "no";
39
40   int numberOfSymbols;
41   
42   //keys for file properties hashmap
43   private final String NAME = "NAME";
44
45   private final String ACCESSION_NUMBER = "ACC";
46
47   private final String DESCRIPTION = "DESC";
48
49   private final String LENGTH = "LENG";
50
51   private final String MAX_LENGTH = "MAXL";
52
53   private final String ALPHABET = "ALPH";
54
55   private final String DATE = "DATE";
56
57   private final String COMMAND_LOG = "COM";
58
59   private final String NUMBER_OF_SEQUENCES = "NSEQ";
60
61   private final String EFF_NUMBER_OF_SEQUENCES = "EFFN";
62
63   private final String CHECK_SUM = "CKSUM";
64
65   private final String GATHERING_THRESHOLDS = "GA";
66
67   private final String TRUSTED_CUTOFFS = "TC";
68
69   private final String NOISE_CUTOFFS = "NC";
70
71   private final String STATISTICS = "STATS";
72
73   private final String COMPO = "COMPO";
74   
75   private final String GATHERING_THRESHOLD = "GA";
76
77   private final String TRUSTED_CUTOFF = "TC";
78
79   private final String NOISE_CUTOFF = "NC";
80
81   private final String VITERBI = "VITERBI";
82
83   private final String MSV = "MSV";
84
85   private final String FORWARD = "FORWARD";
86
87   private final String MAP = "MAP";
88
89   private final String REFERENCE_ANNOTATION = "RF";
90
91   private final String CONSENSUS_RESIDUE = "CONS";
92
93   private final String CONSENSUS_STRUCTURE = "CS";
94
95   private final String MASKED_VALUE = "MM";
96   
97   final static String[] TRANSITION_TYPES = new String[] { "m->m", "m->i",
98       "m->d", "i->m", "i->i", "d->m", "d->d" };
99
100   public String getTransitionType(int index)
101   {
102     return TRANSITION_TYPES[index];
103   }
104
105   public Map<Integer, Integer> getNodeLookup()
106   {
107     return nodeLookup;
108   }
109
110   public void setNodeLookup(Map<Integer, Integer> nodeLookup)
111   {
112     this.nodeLookup = nodeLookup;
113   }
114
115   public String[] getTransitionTypes()
116   {
117     return TRANSITION_TYPES;
118   }
119
120   public List<Character> getSymbols()
121   {
122     return symbols;
123   }
124
125   public Map<String, String> getFileProperties()
126   {
127     return fileProperties;
128   }
129
130   public HMMNode getNode(int nodeIndex)
131   {
132     return getNodes().get(nodeIndex);
133   }
134
135   public void setSymbols(List<Character> symbolsL)
136   {
137     this.symbols = symbolsL;
138   }
139
140   public String getName()
141   {
142     return fileProperties.get(NAME);
143   }
144   public String getAccessionNumber()
145   {
146     return fileProperties.get(ACCESSION_NUMBER);
147   }
148
149   public void setAccessionNumber(String value)
150   {
151     fileProperties.put(ACCESSION_NUMBER, value);
152   }
153
154   public String getDescription()
155   {
156     return fileProperties.get(DESCRIPTION);
157   }
158
159   public void setDescription(String value)
160   {
161     fileProperties.put(DESCRIPTION, value);
162   }
163
164   public Integer getLength()
165   {
166     if (fileProperties.get(LENGTH) == null)
167     {
168       return null;
169     }
170     return Integer.parseInt(fileProperties.get(LENGTH));
171   }
172
173   public void setLength(int value)
174   {
175     fileProperties.put(LENGTH, String.valueOf(value));
176   }
177
178   public Integer getMaxInstanceLength()
179   {
180     if (fileProperties.get(MAX_LENGTH) == null)
181     {
182       return null;
183     }
184     return Integer.parseInt(fileProperties.get(MAX_LENGTH));
185   }
186
187   public void setMaxInstanceLength(int value)
188   {
189     fileProperties.put(MAX_LENGTH, String.valueOf(value));
190   }
191
192   // gets type of symbol alphabet - "amino", "DNA", "RNA"
193   public String getAlphabetType()
194   {
195     return fileProperties.get(ALPHABET);
196   }
197
198   public void setAlphabetType(String value)
199   {
200     fileProperties.put(ALPHABET, value);
201   }
202
203   // not sure whether to implement this with Date object
204   public String getDate()
205   {
206     return fileProperties.get(DATE);
207   }
208
209   public void setDate(String value)
210   {
211     fileProperties.put(DATE, value);
212   }
213
214   // not sure whether to implement this
215   public String getCommandLineLog()
216   {
217     return fileProperties.get(COMMAND_LOG);
218   }
219
220   public void setCommandLineLog(String value)
221   {
222     fileProperties.put(COMMAND_LOG, value);
223   }
224
225   // gets the number of sequences that the HMM was trained on
226   public Integer getNumberOfSequences()
227   {
228     if (fileProperties.get(NUMBER_OF_SEQUENCES) == null)
229     {
230       return null;
231     }
232     return Integer.parseInt(fileProperties.get(NUMBER_OF_SEQUENCES));
233   }
234
235   public void setNumberOfSequences(int value)
236   {
237     fileProperties.put(NUMBER_OF_SEQUENCES, String.valueOf(value));
238   }
239
240   // gets the effective number determined during sequence weighting
241   public Double getEffectiveNumberOfSequences()
242   {
243     if (fileProperties.get(LENGTH) == null)
244     {
245       return null;
246     }
247     return Double.parseDouble(fileProperties.get(EFF_NUMBER_OF_SEQUENCES));
248   }
249
250   public void setEffectiveNumberOfSequences(double value)
251   {
252     fileProperties.put(EFF_NUMBER_OF_SEQUENCES, String.valueOf(value));
253   }
254
255   public Long getCheckSum()
256   {
257     if (fileProperties.get(LENGTH) == null)
258     {
259       return null;
260     }
261     return Long.parseLong(fileProperties.get(CHECK_SUM));
262   }
263
264   public void setCheckSum(long value)
265   {
266     fileProperties.put(CHECK_SUM, String.valueOf(value));
267   }
268
269   public List<HMMNode> getNodes()
270   {
271     return nodes;
272   }
273
274   public void setNodes(List<HMMNode> nodes)
275   {
276     this.nodes = nodes;
277   }
278   
279   /**
280    * get match emission probability for a given symbol at a column in the
281    * alignment
282    * 
283    * @param alignColumn
284    * @param symbol
285    * @return
286    * 
287    */
288   public Double getMatchEmissionProbability(int alignColumn, char symbol)
289   {
290     int symbolIndex;
291     int nodeIndex;
292     Double probability;
293     symbolIndex = symbolIndexLookup.get(symbol);
294     nodeIndex = nodeLookup.get(alignColumn);
295     probability = getNode(nodeIndex).getMatchEmissions().get(symbolIndex);
296     return probability;
297
298   }
299
300   /**
301    * get insert emission probability for a given symbol at a column in the
302    * alignment
303    * 
304    * @param alignColumn
305    * @param symbol
306    * @return
307    */
308   public Double getInsertEmissionProbability(int alignColumn, char symbol)
309   {
310     int symbolIndex;
311     int nodeIndex;
312     Double probability;
313     symbolIndex = symbolIndexLookup.get(symbol);
314     nodeIndex = nodeLookup.get(alignColumn);
315     probability = getNode(nodeIndex).getInsertEmissions().get(symbolIndex);
316     return probability;
317
318   }
319   
320   /**
321    * get state transition probability for a given transition type at a column in
322    * the alignment
323    * 
324    * @param alignColumn
325    * @param transition
326    * @return
327    */
328   public Double getStateTransitionProbability(int alignColumn,
329           String transition)
330   {
331     int transitionIndex;
332     int nodeIndex;
333     Double probability;
334     transitionIndex = getTransitionType(transition);
335     nodeIndex = nodeLookup.get(alignColumn);
336     probability = getNode(nodeIndex).getStateTransitions()
337             .get(transitionIndex);
338     return probability;
339
340   }
341   
342   public Integer getNodeAlignmentColumn(int nodeIndex)
343   {
344     Integer value = nodes.get(nodeIndex).getAlignmentColumn();
345    return value;
346   }
347   
348   public char getConsensusResidue(int nodeIndex)
349   {
350    char value = nodes.get(nodeIndex).getConsensusResidue();
351    return value;
352   }
353   
354   public char getReferenceAnnotation(int nodeIndex)
355   {
356    char value = nodes.get(nodeIndex).getReferenceAnnotation();
357    return value;
358   }
359   
360   public char getMaskedValue(int nodeIndex)
361   {
362    char value = nodes.get(nodeIndex).getMaskValue();
363    return value;
364   }
365   
366   public char getConsensusStructure(int nodeIndex)
367   {
368    char value = nodes.get(nodeIndex).getConsensusStructure();
369    return value;
370   }
371   
372   /**
373    * returns the average match emission for a given symbol
374    * @param symbolIndex
375    * index of symbol
376    * @return
377    * average negative log propbability of a match emission of the given symbol
378    */
379   public double getAverageMatchEmission(int symbolIndex)
380   {
381     double value = nodes.get(0).getMatchEmissions().get(symbolIndex);
382     return value;
383   }
384
385   public int getNumberOfSymbols()
386   {
387     return numberOfSymbols;
388   }
389
390   public void setNumberOfSymbols(int numberOfSymbols)
391   {
392     this.numberOfSymbols = numberOfSymbols;
393   }
394
395   
396
397   /**
398    * fills symbol array and also finds numberOfSymbols
399    * 
400    * @param parser
401    *          scanner scanning symbol line in file
402    */
403   public void fillSymbols(Scanner parser)
404   {
405     int i = 0;
406     while (parser.hasNext())
407     {
408       String strSymbol = parser.next();
409       char[] symbol = strSymbol.toCharArray();
410       symbols.add(symbol[0]);
411       symbolIndexLookup.put(symbol[0], i);
412       i++;
413     }
414     numberOfSymbols = symbols.size();
415   }
416
417   /**
418    * adds file property
419    * 
420    * @param key
421    * @param value
422    */
423   public void addFileProperty(String key, String value)
424   {
425     fileProperties.put(key, value);
426   }
427
428   public boolean referenceAnnotationIsActive()
429   {
430     String status;
431     status = fileProperties.get(REFERENCE_ANNOTATION);
432     if (status == null)
433     {
434       return false;
435     }
436     switch (status)
437     {
438     case YES:
439       return true;
440     case NO:
441       return false;
442     default:
443       return false;
444     }
445
446   }
447
448   public boolean maskValueIsActive()
449   {
450     String status;
451     status = fileProperties.get(MASKED_VALUE);
452     if (status == null)
453     {
454       return false;
455     }
456     switch (status)
457     {
458     case YES:
459       return true;
460     case NO:
461       return false;
462     default:
463       return false;
464     }
465
466   }
467
468   public boolean consensusResidueIsActive()
469   {
470     String status;
471     status = fileProperties.get(CONSENSUS_RESIDUE);
472     if (status == null)
473     {
474       return false;
475     }
476     switch (status)
477     {
478     case YES:
479       return true;
480     case NO:
481       return false;
482     default:
483       return false;
484     }
485
486   }
487
488   public boolean consensusStructureIsActive()
489   {
490     String status;
491     status = fileProperties.get(CONSENSUS_STRUCTURE);
492     if (status == null)
493     {
494       return false;
495     }
496     switch (status)
497     {
498     case YES:
499       return true;
500     case NO:
501       return false;
502     default:
503       return false;
504     }
505
506   }
507
508   public boolean mapIsActive()
509   {
510     String status;
511     status = fileProperties.get(MAP);
512     if (status == null)
513     {
514       return false;
515     }
516     switch (status)
517     {
518     case YES:
519       return true;
520     case NO:
521       return false;
522     default:
523       return false;
524     }
525
526   }
527
528   public void setAlignmentColumn(int nodeIndex, int column)
529   {
530     nodes.get(nodeIndex).setAlignmentColumn(column);
531   }
532
533   public void setReferenceAnnotation(int nodeIndex, char value)
534   {
535     nodes.get(nodeIndex).setReferenceAnnotation(value);
536   }
537
538   public void setConsensusResidue(int nodeIndex, char value)
539   {
540     nodes.get(nodeIndex).setConsensusResidue(value);
541   }
542
543   public void setConsensusStructure(int nodeIndex, char value)
544   {
545     nodes.get(nodeIndex).setConsensusStructure(value);
546   }
547
548   public void setMaskValue(int nodeIndex, char value)
549   {
550     nodes.get(nodeIndex).setMaskValue(value);
551   }
552
553   public String getGatheringThreshold()
554   {
555     String value;
556     value = fileProperties.get("GA");
557     return value;
558   }
559
560   public String getNoiseCutoff()
561   {
562     String value;
563     value = fileProperties.get("NC");
564     return value;
565   }
566
567   public String getTrustedCutoff()
568   {
569     String value;
570     value = fileProperties.get("TC");
571     return value;
572   }
573
574   public String getViterbi()
575   {
576     String value;
577     value = fileProperties.get(VITERBI);
578     return value;
579   }
580
581   public String getMSV()
582   {
583     String value;
584     value = fileProperties.get(MSV);
585     return value;
586   }
587
588   public String getForward()
589   {
590     String value;
591     value = fileProperties.get(FORWARD);
592     return value;
593   }
594
595   public void setMAPStatus(boolean status)
596   {
597     if (status == true)
598     {
599       fileProperties.put(MAP, YES);
600     }
601     else
602     {
603       fileProperties.put(MAP, NO);
604     }
605   }
606
607   public void setReferenceAnnotationStatus(boolean status)
608   {
609     if (status == true)
610     {
611       fileProperties.put(REFERENCE_ANNOTATION, YES);
612     }
613     else
614     {
615       fileProperties.put(REFERENCE_ANNOTATION, NO);
616     }
617   }
618
619   public void setMaskedValueStatus(boolean status)
620   {
621     if (status == true)
622     {
623       fileProperties.put(MASKED_VALUE, YES);
624     }
625     else
626     {
627       fileProperties.put(MASKED_VALUE, NO);
628     }
629   }
630
631   public void setConsensusResidueStatus(boolean status)
632   {
633     if (status == true)
634     {
635       fileProperties.put(CONSENSUS_RESIDUE, YES);
636     }
637     else
638     {
639       fileProperties.put(CONSENSUS_RESIDUE, NO);
640     }
641   }
642
643   public void setConsensusStructureStatus(boolean status)
644   {
645     if (status == true)
646     {
647       fileProperties.put(CONSENSUS_STRUCTURE, YES);
648     }
649     else
650     {
651       fileProperties.put(CONSENSUS_STRUCTURE, NO);
652     }
653   }
654
655   /**
656    * 
657    * @param transition
658    *          type of transition occuring
659    * @return index value representing position along stateTransition array.
660    */
661   public Integer getTransitionType(String transition)
662   {
663     Integer index;
664     switch (transition)
665     {
666     case "mm":
667       index = 0;
668       break;
669     case "mi":
670       index = 1;
671       break;
672     case "md":
673       index = 2;
674       break;
675     case "im":
676       index = 3;
677       break;
678     case "ii":
679       index = 4;
680       break;
681     case "dm":
682       index = 5;
683       break;
684     case "dd":
685       index = 6;
686       break;
687     default:
688       index = null;
689     }
690     return index;
691   }
692
693   /**
694    * find the index of the node in a hidden Markov model based on the column in
695    * the alignment
696    * 
697    * @param alignmentColumn
698    */
699
700   public Integer findNodeIndex(int alignmentColumn)
701   {
702     Integer index;
703     index = nodeLookup.get(alignmentColumn);
704     return index;
705   }
706
707   public static String findStringFromBoolean(boolean value)
708   {
709     if (value)
710     {
711       return YES;
712     }
713     else
714     {
715       return NO;
716     }
717   }
718 }
719