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.dist;
024
025import java.io.Serializable;
026import java.util.HashMap;
027import java.util.Iterator;
028import java.util.Map;
029
030import org.biojava.bio.BioError;
031import org.biojava.bio.symbol.Alphabet;
032import org.biojava.bio.symbol.AtomicSymbol;
033import org.biojava.bio.symbol.FiniteAlphabet;
034import org.biojava.bio.symbol.IllegalAlphabetException;
035import org.biojava.bio.symbol.IllegalSymbolException;
036import org.biojava.bio.symbol.Symbol;
037import org.biojava.utils.ChangeVetoException;
038
039/**
040 * A simple implemenation of a distribution trainer.
041 * <p>
042 * This requires the distribuiton being trained to have a working setWeight
043 * method that doesn't throw an UnsupportedOperationExcepiton.
044 * </p>
045 *
046 * @author Matthew Pocock
047 * @deprecated  Distribution impls should be providing custom trainers.
048 */
049
050public final class SimpleDistributionTrainer
051implements DistributionTrainer, Serializable {
052  private final Distribution dis;
053  private final Map c;
054
055  {
056    this.c = new HashMap();
057  }
058
059  public void addCount(
060    DistributionTrainerContext dtc,
061    AtomicSymbol sym,
062    double count
063  ) throws IllegalSymbolException {
064    Double d = (Double) c.get(sym);
065    if (d == null) {
066      throw new IllegalSymbolException(
067        "Symbol " + sym.getName() +
068        " not found in " + dis.getAlphabet().getName()
069      );
070    }
071    if(count < 0) {
072      throw new Error(
073        "Can't add a negative count for " + sym.getName() +
074        " of " + count
075      );
076    }
077    c.put(sym, new Double(d.doubleValue() + count));
078  }
079
080  public double getCount(
081    DistributionTrainerContext dtc,
082    AtomicSymbol sym
083  ) throws IllegalSymbolException {
084    Double d = (Double) c.get(sym);
085    if (d == null) {
086      throw new IllegalSymbolException(
087        "Symbol " + sym.getName() +
088        " not found in " + dis.getAlphabet().getName()
089      );
090    }
091    return ((Double) c.get(sym)).doubleValue();
092  }
093
094  public void train(DistributionTrainerContext dtc, double weight)
095  throws ChangeVetoException {
096    Distribution nullModel = dis.getNullModel();
097    double sum = 0.0;
098    try {
099      for(
100        Iterator i = ((FiniteAlphabet) dis.getAlphabet()).iterator();
101        i.hasNext();
102      ) {
103        Symbol s = (Symbol) i.next();
104        Double d = (Double) c.get(s);
105        sum += d.doubleValue() +
106             nullModel.getWeight(s) * weight;
107             // System.out.println(s.getName() + ": sum=" + sum);
108      }
109      for(
110        Iterator i = ((FiniteAlphabet) dis.getAlphabet()).iterator();
111        i.hasNext();
112      ) {
113        Symbol sym = (Symbol) i.next();
114        Double d = (Double) c.get(sym);
115        dis.setWeight(
116          sym,
117          (d.doubleValue() + nullModel.getWeight(sym) * weight) / sum
118        );
119      }
120    } catch (IllegalSymbolException ise) {
121      throw new BioError(
122        "The alphabet for this distribution is not self-consistent"
123      );
124    }
125  }
126
127  public void clearCounts(DistributionTrainerContext dtc) {
128    for(
129      Iterator i = ((FiniteAlphabet) dis.getAlphabet()).iterator();
130      i.hasNext();
131    ) {
132      c.put(i.next(), new Double(0.0));
133    }
134  }
135
136  public SimpleDistributionTrainer(Distribution dis)
137  throws IllegalAlphabetException {
138    Alphabet a = dis.getAlphabet();
139    if(! (a instanceof FiniteAlphabet)) {
140      throw new IllegalAlphabetException(
141        "Can't create a SimpleDistributionTrainer for non-finite alphabet " +
142        a.getName() + " of type " + a.getClass()
143      );
144    }
145    this.dis = dis;
146  }
147}