001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022
023package org.biojava.bio.dp;
024
025import java.io.ObjectStreamException;
026import java.io.Serializable;
027import java.util.HashMap;
028import java.util.Map;
029
030import org.biojava.bio.Annotation;
031import org.biojava.bio.dist.GapDistribution;
032import org.biojava.bio.symbol.Alphabet;
033
034/**
035 * Start/end state for HMMs.
036 * <p>
037 * All MagicalState objects emit over MAGICAL_ALPHABET, which only contains
038 * MAGICAL_STATE.
039 *
040 * @author Matthew Pocock
041 */
042public final class MagicalState extends SimpleEmissionState {
043  /**
044   * A cache of magical state objects so that we avoid making the same
045   * thing twice.
046   */
047  private static final Map stateCache;
048  static {
049    stateCache = new HashMap();
050  }
051  
052  public static MagicalState getMagicalState(Alphabet alphabet, int heads) {
053    AlphaHeads ah = new AlphaHeads(alphabet, heads);
054    MagicalState ms = (MagicalState) stateCache.get(ah);
055    if(ms == null) {
056      ms = new MagicalState(alphabet, heads);
057      stateCache.put(ah, ms);
058    }
059    return ms;
060  }
061
062  private MagicalState(Alphabet alpha, int heads) {
063    super(
064      "!-" + heads,
065      Annotation.EMPTY_ANNOTATION,
066      new int[heads],
067      new GapDistribution(alpha)
068    );
069    int [] advance = getAdvance();
070    for(int i = 0; i < heads; i++) {
071      advance[i] = 1;
072    }
073  }
074
075  private Object writeReplace() throws ObjectStreamException {
076    return new PlaceHolder(getDistribution().getAlphabet(), getAdvance().length);
077  }
078  
079  private static class AlphaHeads {
080    public Alphabet alpha;
081    public int heads;
082    
083    public AlphaHeads(Alphabet alpha, int heads) {
084      this.alpha = alpha;
085      this.heads = heads;
086    }
087    
088    public boolean equals(Object o) {
089      AlphaHeads ah = (AlphaHeads) o;
090      return this.alpha == ah.alpha && this.heads == ah.heads;
091    }
092    
093    public int hashCode() {
094      return alpha.hashCode() ^ heads;
095    }
096  }
097  
098  private static class PlaceHolder implements Serializable {
099    private Alphabet alpha;
100    private int heads;
101    
102    public PlaceHolder(Alphabet alpha, int heads) {
103      this.alpha = alpha;
104      this.heads = heads;
105    }
106    
107    public Object readResolve() throws ObjectStreamException {
108      return MagicalState.getMagicalState(alpha, heads);
109    }
110  }
111}
112