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.twohead;
024
025import java.io.File;
026import java.io.FileNotFoundException;
027import java.io.FileOutputStream;
028import java.io.IOException;
029import java.io.OutputStream;
030import java.io.PrintStream;
031import java.lang.reflect.Constructor;
032import java.lang.reflect.InvocationTargetException;
033import java.util.HashMap;
034import java.util.Iterator;
035import java.util.Map;
036
037import org.biojava.bio.BioError;
038import org.biojava.bio.BioException;
039import org.biojava.bio.dist.Distribution;
040import org.biojava.bio.dp.BackPointer;
041import org.biojava.bio.dp.DP;
042import org.biojava.bio.dp.EmissionState;
043import org.biojava.bio.dp.IllegalTransitionException;
044import org.biojava.bio.dp.MagicalState;
045import org.biojava.bio.dp.MarkovModel;
046import org.biojava.bio.dp.ScoreType;
047import org.biojava.bio.dp.State;
048import org.biojava.bio.symbol.AlphabetIndex;
049import org.biojava.bio.symbol.AlphabetManager;
050import org.biojava.bio.symbol.FiniteAlphabet;
051import org.biojava.bio.symbol.IllegalAlphabetException;
052import org.biojava.bio.symbol.IllegalSymbolException;
053import org.biojava.bio.symbol.Symbol;
054import org.biojava.utils.ClassTools;
055import org.biojava.utils.bytecode.ByteCode;
056import org.biojava.utils.bytecode.CodeClass;
057import org.biojava.utils.bytecode.CodeException;
058import org.biojava.utils.bytecode.CodeField;
059import org.biojava.utils.bytecode.CodeGenerator;
060import org.biojava.utils.bytecode.CodeMethod;
061import org.biojava.utils.bytecode.CodeUtils;
062import org.biojava.utils.bytecode.GeneratedClassLoader;
063import org.biojava.utils.bytecode.GeneratedCodeClass;
064import org.biojava.utils.bytecode.GeneratedCodeMethod;
065import org.biojava.utils.bytecode.IfExpression;
066import org.biojava.utils.bytecode.InstructionVector;
067import org.biojava.utils.bytecode.IntrospectedCodeClass;
068import org.biojava.utils.bytecode.LocalVariable;
069
070/**
071 * This is an implementation of CellCalculatorFactoryMaker that compiles the
072 * HMM object down to Java byte-code that is equivalent in behaviour to the
073 * interpreter.
074 *
075 * @author Matthew Pocock
076 * @author Greg Cox
077 * @since 1.1
078 */
079
080public class DPCompiler implements CellCalculatorFactoryMaker {
081  //private final boolean debug = false;
082  private final boolean debug = true;
083
084  private final boolean dumpToDisk;
085
086  private final GeneratedClassLoader classLoader;
087
088  public DPCompiler(boolean dumpToDisk) {
089    this.dumpToDisk = dumpToDisk;
090    classLoader = new GeneratedClassLoader(ClassTools.getClassLoader(this));
091  }
092
093  public CellCalculatorFactory make(DP dp) {
094    Class forwardC = generateForardClass(dp);
095    Class backwardC = generateBackwardClass(dp);
096    Class viterbiC = generateViterbiClass(dp);
097
098    try {
099      Constructor forward = forwardC.getConstructor(new Class[] {
100        DP.class,
101        ScoreType.class
102      });
103      Constructor backward = backwardC.getConstructor(new Class[] {
104        DP.class,
105        ScoreType.class
106      });
107      Constructor viterbi = viterbiC.getConstructor(new Class[] {
108        DP.class,
109        ScoreType.class,
110        BackPointer.class
111      });
112      return new Factory(dp, forward, backward, viterbi);
113    } catch (NoSuchMethodException nsme) {
114      throw new BioError("Couldn't find constructor on generated class", nsme);
115    }
116  }
117
118  public static String makeName(String prefix, MarkovModel model) {
119    StringBuffer nameBuffer = new StringBuffer(prefix);
120
121    for(Iterator i = model.stateAlphabet().iterator(); i.hasNext(); ) {
122      nameBuffer.append("_");
123      try {
124        nameBuffer.append(model.transitionsFrom((State) i.next()).size());
125      } catch (IllegalSymbolException ise) {
126        throw new BioError(
127          "Assertion Failure: State dissapeared from model", ise
128        );
129      }
130    }
131
132    return nameBuffer.substring(0);
133  }
134
135  public Class generateForardClass(DP dp) {
136    // forward recursion is:
137    //
138    // score[state_i] =
139    //   emission * sum_j(prev_score[state_j] * transition[state_j, state_i])
140    //
141    // where prev_score is found as score[advance_i[0][advance_i[1]]
142    // however, in log space (as we use), this becomes:
143    //
144    // score[state_i] =
145    //   emission + log( sum_j (
146    //     exp(prev_score[state_j] + transition[state_i, state_j])
147    //   ))
148    //
149    // In practice, for sequences of any length, the sum terms are too
150    // near to zero for numerical instablilty not to play a huge part. So, we
151    // take out a factor of max_j( prev_score[state_j] ) from the sum and add
152    // it to the total.
153    //
154    // score[state_i] =
155    //   emission + log( sum_j (
156    //     exp(transition[state_i, state_j] + (prev_score[state_j]- factor) )
157    //   )) + factor
158
159
160    try {
161      MarkovModel model = dp.getModel();
162
163      String name = makeName("org.biojava.bio.dp.twohead.Forward", model);
164      if(!classLoader.hasGeneratedClass(name)) {
165        CodeClass _Object = IntrospectedCodeClass.forClass(Object.class);
166        CodeClass _DP = IntrospectedCodeClass.forClass(DP.class);
167        CodeClass _ScoreType = IntrospectedCodeClass.forClass(ScoreType.class);
168        CodeClass _State_A = IntrospectedCodeClass.forClass(State [].class);
169        CodeClass _Cell_A_A = IntrospectedCodeClass.forClass(Cell [][].class);
170        CodeClass _CellCalculator = IntrospectedCodeClass.forClass(CellCalculator.class);
171
172        GeneratedCodeClass clazz = new GeneratedCodeClass(
173          name,
174          _Object,
175          new CodeClass[] {_CellCalculator},
176          CodeUtils.ACC_PUBLIC | CodeUtils.ACC_STRICT
177        );
178
179        State[] states = dp.getStates();
180        AlphabetIndex stateIndexer = AlphabetManager.getAlphabetIndex(states);
181
182        CodeField stateF = clazz.createField(
183          "states",
184          _State_A,
185          CodeUtils.ACC_PROTECTED
186        );
187
188        // The fields that contain transition scores as double [].
189        // This is built so that if two states shair the same transition
190        // distribution, they refer to the same transition field. This gives
191        // good optimizers a fighting chance to do some hard-core optimizations.
192        CodeField[] transitionFields = new CodeField[states.length];
193        AlphabetIndex[] transitionIndexers = new AlphabetIndex[states.length];
194
195        // The constructor must load in the transition probabilities.
196        // It uses the indexToFieldIndex to ensure that parameters are loaded
197        // just once.
198        GeneratedCodeMethod __init = clazz.createMethod(
199          "<init>",
200          CodeUtils.TYPE_VOID,
201          new CodeClass[] {_DP, _ScoreType },
202          new String[] { "dp", "scoreType" },
203          CodeUtils.ACC_PUBLIC
204        );
205
206        clazz.setCodeGenerator(__init, createInit(
207          model, states,
208          clazz, __init,
209          transitionIndexers, transitionFields,
210          stateF, null
211        ));
212
213        GeneratedCodeMethod initialize = clazz.createMethod(
214          "initialize",
215          CodeUtils.TYPE_VOID,
216          new CodeClass[] {_Cell_A_A},
217          new String[] { "cells" },
218          CodeUtils.ACC_PUBLIC
219        );
220        clazz.setCodeGenerator(
221          initialize,
222          createFRecursion(
223            true,
224            model, states, stateIndexer,
225            stateF, transitionFields, transitionIndexers,
226            initialize
227          )
228        );
229
230        GeneratedCodeMethod calcCell = clazz.createMethod(
231          "calcCell",
232          CodeUtils.TYPE_VOID,
233          new CodeClass[] {_Cell_A_A },
234          new String[] { "cells" },
235          CodeUtils.ACC_PUBLIC
236        );
237        clazz.setCodeGenerator(
238        calcCell,
239        createFRecursion(
240          false,
241          model, states, stateIndexer,
242          stateF, transitionFields, transitionIndexers,
243          calcCell
244        )
245      );
246
247      if(dumpToDisk == true) {
248        try {
249          StringBuffer fName = new StringBuffer(name);
250          for(int i = 0; i < fName.length(); i++) {
251            if(fName.charAt(i) == '.') {
252              fName.setCharAt(i, '/');
253            }
254          }
255          fName.append(".class");
256
257          File dumpFile = new File(fName.substring(0));
258          System.out.println("Dumping file: " + fName);
259          dumpFile.getParentFile().mkdirs();
260
261          OutputStream out = new FileOutputStream(dumpFile);
262          clazz.createCode(out);
263          out.close();
264        } catch (FileNotFoundException fnfe) {
265          throw new BioError("Couldn't dump dp class", fnfe);
266        } catch (IOException ioe) {
267          throw new BioError("Couldn't dump dp class", ioe);
268        }
269      }
270
271      classLoader.defineClass(clazz);
272    }
273     try {
274          return classLoader.loadClass(name);
275        } catch (Exception e) {
276          throw new BioError("Can't find previously generated class for " + name, e);
277        }
278    } catch (CodeException ce) {
279      throw new BioError("Couldn't generate class", ce);
280    } catch (NoSuchMethodException nsme) {
281      throw new BioError( "Couldn't find method", nsme);
282    } catch (NoSuchFieldException nsfe) {
283      throw new BioError("Couldn't find field", nsfe);
284    } catch (IllegalSymbolException ise) {
285      throw new BioError("Couldn't find symbol", ise);
286    } catch (BioException be) {
287      throw new BioError("Couldn't create indexer", be);
288    }
289  }
290
291  public Class generateBackwardClass(DP dp) {
292    // backward recursion is:
293    // score[state_i] =
294    //   sum_j(prev_score[state_j] * transition[state_i, state_j] * emission[j])
295    // where prev_score is found as score[advance_j[0][advance_j[1]]
296    // however, in log space (as we use), this becomes:
297    // score[state_i] =
298    //   emission + log( sum_j (
299    //     exp(prev_score[state_j] + transition[state_j, state_i)
300    //   ))
301    //
302    // In practice, for sequences of any length, the sum terms are too
303    // near to zero for numerical instablilty not to play a huge part. So, we
304    // take out a factor of max_j( prev_score[state_j] ) from the sum and add
305    // it to the total.
306
307    try {
308      MarkovModel model = dp.getModel();
309
310      String name = makeName("org.biojava.bio.dp.twohead.Backward", model);
311      if(!classLoader.hasGeneratedClass(name)) {
312        CodeClass _Object = IntrospectedCodeClass.forClass(Object.class);
313        CodeClass _DP = IntrospectedCodeClass.forClass(DP.class);
314        CodeClass _ScoreType = IntrospectedCodeClass.forClass(ScoreType.class);
315        CodeClass _State_A = IntrospectedCodeClass.forClass(State [].class);
316        CodeClass _Cell_A_A = IntrospectedCodeClass.forClass(Cell [][].class);
317        CodeClass _CellCalculator = IntrospectedCodeClass.forClass(CellCalculator.class);
318
319        GeneratedCodeClass clazz = new GeneratedCodeClass(
320          name,
321          _Object,
322          new CodeClass[] {_CellCalculator},
323          CodeUtils.ACC_PUBLIC | CodeUtils.ACC_STRICT
324        );
325
326        State[] states = dp.getStates();
327        AlphabetIndex stateIndexer = AlphabetManager.getAlphabetIndex(states);
328
329        CodeField stateF = clazz.createField(
330          "states",
331          _State_A,
332          CodeUtils.ACC_PROTECTED
333        );
334
335        // The fields that contain transition scores as double [].
336        // This is built so that if two states shair the same transition
337        // distribution, they refer to the same transition field. This gives
338        // good optimizers a fighting chance to do some hard-core optimizations.
339        CodeField[] transitionFields = new CodeField[states.length];
340        AlphabetIndex[] transitionIndexers = new AlphabetIndex[states.length];
341
342        // The constructor must load in the transition probabilities.
343        // It uses the indexToFieldIndex to ensure that parameters are loaded
344        // just once.
345        GeneratedCodeMethod __init = clazz.createMethod(
346          "<init>",
347          CodeUtils.TYPE_VOID,
348          new CodeClass[] {_DP, _ScoreType },
349          new String[] { "dp", "scoreType" },
350          CodeUtils.ACC_PUBLIC
351        );
352
353        clazz.setCodeGenerator(__init, createInit(
354          model, states,
355          clazz, __init,
356          transitionIndexers, transitionFields,
357          stateF, null
358        ));
359
360        GeneratedCodeMethod initialize = clazz.createMethod(
361          "initialize",
362          CodeUtils.TYPE_VOID,
363          new CodeClass[] {_Cell_A_A},
364          new String[] { "cells" },
365          CodeUtils.ACC_PUBLIC
366        );
367        clazz.setCodeGenerator(
368          initialize,
369          createBRecursion(
370            true,
371            model, states, stateIndexer,
372            stateF, transitionFields, transitionIndexers,
373            initialize
374          )
375        );
376
377        GeneratedCodeMethod calcCell = clazz.createMethod(
378          "calcCell",
379          CodeUtils.TYPE_VOID,
380          new CodeClass[] {_Cell_A_A },
381          new String[] { "cells" },
382          CodeUtils.ACC_PUBLIC
383        );
384        clazz.setCodeGenerator(
385        calcCell,
386        createBRecursion(
387          false,
388          model, states, stateIndexer,
389          stateF, transitionFields, transitionIndexers,
390          calcCell
391        )
392      );
393
394      if(dumpToDisk == true) {
395        try {
396          StringBuffer fName = new StringBuffer(name);
397          for(int i = 0; i < fName.length(); i++) {
398            if(fName.charAt(i) == '.') {
399              fName.setCharAt(i, '/');
400            }
401          }
402          fName.append(".class");
403
404          File dumpFile = new File(fName.substring(0));
405          System.out.println("Dumping file: " + fName);
406          dumpFile.getParentFile().mkdirs();
407
408          OutputStream out = new FileOutputStream(dumpFile);
409          clazz.createCode(out);
410          out.close();
411        } catch (FileNotFoundException fnfe) {
412          throw new BioError( "Couldn't dump dp class", fnfe);
413        } catch (IOException ioe) {
414          throw new BioError( "Couldn't dump dp class", ioe);
415        }
416      }
417
418      classLoader.defineClass(clazz);
419    }
420     try {
421          return classLoader.loadClass(name);
422        } catch (Exception e) {
423          throw new BioError("Can't find previously generated class for " + name, e);
424        }
425    } catch (CodeException ce) {
426      throw new BioError("Couldn't generate class", ce);
427    } catch (NoSuchMethodException nsme) {
428      throw new BioError( "Couldn't find method", nsme);
429    } catch (NoSuchFieldException nsfe) {
430      throw new BioError( "Couldn't find field", nsfe);
431    } catch (IllegalSymbolException ise) {
432      throw new BioError( "Couldn't find symbol", ise);
433    } catch (BioException be) {
434      throw new BioError( "Couldn't create indexer", be);
435    }
436  }
437
438  public Class generateViterbiClass(DP dp) {
439    // viterbi recursion is:
440    // score[state_i] =
441    //   emission * max_j(prev_score[state_j] * transition[state_j, state_i])
442    // however, in log space (as we use), this becomes:
443    // score[state_i] =
444    //   emission + max_j(
445    //     prev_score[state_j] + transition[state_j, state_i]
446    //   ))
447
448    try {
449      MarkovModel model = dp.getModel();
450
451      String name = makeName("org.biojava.bio.dp.twohead.Viterbi", model);
452      if(!classLoader.hasGeneratedClass(name)) {
453
454      CodeClass _Object = IntrospectedCodeClass.forClass(Object.class);
455      CodeClass _DP = IntrospectedCodeClass.forClass(DP.class);
456      CodeClass _BackPointer = IntrospectedCodeClass.forClass(BackPointer.class);
457      CodeClass _ScoreType = IntrospectedCodeClass.forClass(ScoreType.class);
458      CodeClass _State_A = IntrospectedCodeClass.forClass(State [].class);
459      CodeClass _Cell_A_A = IntrospectedCodeClass.forClass(Cell [][].class);
460      CodeClass _CellCalculator = IntrospectedCodeClass.forClass(CellCalculator.class);
461
462      GeneratedCodeClass clazz = new GeneratedCodeClass(
463        name,
464        _Object,
465        new CodeClass[] {_CellCalculator},
466        CodeUtils.ACC_PUBLIC | CodeUtils.ACC_STRICT
467      );
468
469      State[] states = dp.getStates();
470      AlphabetIndex stateIndexer = AlphabetManager.getAlphabetIndex(states);
471
472      CodeField terminalBP = clazz.createField(
473        "terminalBP",
474        _BackPointer,
475        CodeUtils.ACC_PROTECTED
476      );
477
478      CodeField stateF = clazz.createField(
479        "states",
480        _State_A,
481        CodeUtils.ACC_PROTECTED
482      );
483
484      // The fields that contain transition scores as double [].
485      // This is built so that if two states shair the same transition
486      // distribution, they refer to the same transition field. This gives
487      // good optimizers a fighting chance to do some hard-core optimizations.
488      CodeField[] transitionFields = new CodeField[states.length];
489      AlphabetIndex[] transitionIndexers = new AlphabetIndex[states.length];
490
491      // The constructor must load in the transition probabilities.
492      // It uses the indexToFieldIndex to ensure that parameters are loaded
493      // just once.
494      GeneratedCodeMethod __init = clazz.createMethod(
495        "<init>",
496        CodeUtils.TYPE_VOID,
497        new CodeClass[] {_DP, _ScoreType, _BackPointer },
498        new String[] { "dp", "scoreType", "backPointer" },
499        CodeUtils.ACC_PUBLIC
500      );
501
502      clazz.setCodeGenerator(__init, createInit(
503        model, states,
504        clazz, __init,
505        transitionIndexers, transitionFields,
506        stateF, terminalBP
507      ));
508
509      GeneratedCodeMethod initialize = clazz.createMethod(
510        "initialize",
511        CodeUtils.TYPE_VOID,
512        new CodeClass[] {_Cell_A_A},
513        new String[] { "cells" },
514        CodeUtils.ACC_PUBLIC
515      );
516      clazz.setCodeGenerator(
517        initialize,
518        createVRecursion(
519          true,
520          model, states, stateIndexer,
521          stateF, transitionFields, transitionIndexers,
522          terminalBP,
523          initialize
524        )
525      );
526
527      GeneratedCodeMethod calcCell = clazz.createMethod(
528        "calcCell",
529        CodeUtils.TYPE_VOID,
530        new CodeClass[] {_Cell_A_A },
531        new String[] { "cells" },
532        CodeUtils.ACC_PUBLIC
533      );
534      clazz.setCodeGenerator(
535        calcCell,
536        createVRecursion(
537          false,
538          model, states, stateIndexer,
539          stateF, transitionFields, transitionIndexers,
540          terminalBP,
541          calcCell
542        )
543      );
544
545      if(dumpToDisk == true) {
546        try {
547          StringBuffer fName = new StringBuffer(name);
548          for(int i = 0; i < fName.length(); i++) {
549            if(fName.charAt(i) == '.') {
550              fName.setCharAt(i, '/');
551            }
552          }
553          fName.append(".class");
554
555          File dumpFile = new File(fName.substring(0));
556          System.out.println("Dumping file: " + fName);
557          dumpFile.getParentFile().mkdirs();
558
559          OutputStream out = new FileOutputStream(dumpFile);
560          clazz.createCode(out);
561          out.close();
562        } catch (FileNotFoundException fnfe) {
563          throw new BioError( "Couldn't dump dp class", fnfe);
564        } catch (IOException ioe) {
565          throw new BioError( "Couldn't dump dp class", ioe);
566        }
567      }
568
569      classLoader.defineClass(clazz);
570    }
571     try {
572          return classLoader.loadClass(name);
573        } catch (Exception e) {
574          throw new BioError( "Can't find previously generated class for " + name, e);
575        }
576    } catch (CodeException ce) {
577      throw new BioError( "Couldn't generate class", ce);
578    } catch (NoSuchMethodException nsme) {
579      throw new BioError( "Couldn't find method", nsme);
580    } catch (NoSuchFieldException nsfe) {
581      throw new BioError( "Couldn't find field", nsfe);
582    } catch (IllegalSymbolException ise) {
583      throw new BioError( "Couldn't find symbol", ise);
584    } catch (BioException be) {
585      throw new BioError( "Couldn't create indexer", be);
586    }
587  }
588
589  CodeGenerator createVRecursion(
590    boolean isInit,
591    MarkovModel model,
592    State[] states,
593    AlphabetIndex stateIndex,
594    CodeField stateF,
595    CodeField [] transitionFields,
596    AlphabetIndex[] transitionIndexers,
597    CodeField terminalBP,
598    GeneratedCodeMethod method
599  ) throws
600    NoSuchMethodException,
601    NoSuchFieldException,
602    IllegalSymbolException,
603    CodeException
604  {
605    CodeClass _Cell = IntrospectedCodeClass.forClass(Cell.class);
606    CodeField _Cell_score = _Cell.getFieldByName("scores");
607    CodeField _Cell_backpointer = _Cell.getFieldByName("backPointers");
608    CodeField _Cell_emissions = _Cell.getFieldByName("emissions");
609    CodeClass _State = IntrospectedCodeClass.forClass(State.class);
610    CodeClass _BackPointer = IntrospectedCodeClass.forClass(BackPointer.class);
611    CodeClass _BackPointer_A = IntrospectedCodeClass.forClass(BackPointer [].class);
612    CodeMethod _BackPointer_init = _BackPointer.getConstructor(new CodeClass [] {_State, _BackPointer, CodeUtils.TYPE_DOUBLE});
613    CodeClass _double_A = IntrospectedCodeClass.forClass(double [].class);
614
615    InstructionVector ccV = new InstructionVector();
616
617    // if(isInit && state instanceof emission) {
618    //   cell[0][0] = (state == Magical) ? 0.0 : NaN;
619    // } else {
620    //   cell[0][0].score[i] = cell[0][0].emissions[i] +
621    //                         max_j(cell[adv_i_0][adv_i_1] + t_j[i])
622    // }
623
624    // cell_00 = cell[0][0];
625    // cell_01 = cell[0][1];
626    // cell_10 = cell[1][0];
627    // cell_11 = cell[1][1];
628    LocalVariable[][] cell = new LocalVariable[2][2];
629    cell[0][0] = new LocalVariable(_Cell, "cell_00");
630    cell[0][1] = new LocalVariable(_Cell, "cell_01");
631    cell[1][0] = new LocalVariable(_Cell, "cell_10");
632    cell[1][1] = new LocalVariable(_Cell, "cell_11");
633
634    ccV.add( ByteCode.make_aload  (method.getVariable("cells")));
635    ccV.add( ByteCode.make_dup    ());
636    ccV.add( ByteCode.make_iconst (0));
637    ccV.add( ByteCode.make_aaload ());
638    ccV.add( ByteCode.make_dup    ());
639    ccV.add( ByteCode.make_iconst (0));
640    ccV.add( ByteCode.make_aaload ());
641    ccV.add( ByteCode.make_astore (cell[0][0]));
642    ccV.add( ByteCode.make_iconst (1));
643    ccV.add( ByteCode.make_aaload ());
644    ccV.add( ByteCode.make_astore (cell[0][1]));
645    ccV.add( ByteCode.make_iconst (1));
646    ccV.add( ByteCode.make_aaload ());
647    ccV.add( ByteCode.make_dup    ());
648    ccV.add( ByteCode.make_iconst (0));
649    ccV.add( ByteCode.make_aaload ());
650    ccV.add( ByteCode.make_astore (cell[1][0]));
651    ccV.add( ByteCode.make_iconst (1));
652    ccV.add( ByteCode.make_aaload ());
653    ccV.add( ByteCode.make_astore (cell[1][1]));
654
655    // score_00 = cell[0][0].score;
656    // score_01 = cell[0][1].score;
657    // score_10 = cell[1][0].score;
658    // score_11 = cell[1][1].score;
659
660    LocalVariable[][] score = new LocalVariable[2][2];
661    score[0][0] = new LocalVariable(_double_A, "score_00");
662    score[0][1] = new LocalVariable(_double_A, "score_01");
663    score[1][0] = new LocalVariable(_double_A, "score_10");
664    score[1][1] = new LocalVariable(_double_A, "score_11");
665    ccV.add( ByteCode.make_aload    (cell[0][0]));
666    ccV.add( ByteCode.make_getfield ( _Cell_score));
667    ccV.add( ByteCode.make_astore   (score[0][0]));
668    ccV.add( ByteCode.make_aload    (cell[0][1]));
669    ccV.add( ByteCode.make_getfield ( _Cell_score));
670    ccV.add( ByteCode.make_astore   (score[0][1]));
671    ccV.add( ByteCode.make_aload    (cell[1][0]));
672    ccV.add( ByteCode.make_getfield ( _Cell_score));
673    ccV.add( ByteCode.make_astore   (score[1][0]));
674    ccV.add( ByteCode.make_aload    (cell[1][1]));
675    ccV.add( ByteCode.make_getfield ( _Cell_score));
676    ccV.add( ByteCode.make_astore   (score[1][1]));
677
678    // backpointer_00 = cell[0][0].backpointer;
679    // backpointer_01 = cell[0][1].backpointer;
680    // backpointer_10 = cell[1][0].backpointer;
681    // backpointer_11 = cell[1][1].backpointer;
682
683    LocalVariable[][] backpointer = new LocalVariable[2][2];
684    backpointer[0][0] = new LocalVariable(_BackPointer_A, "backpointer_00");
685    backpointer[0][1] = new LocalVariable(_BackPointer_A, "backpointer_01");
686    backpointer[1][0] = new LocalVariable(_BackPointer_A, "backpointer_10");
687    backpointer[1][1] = new LocalVariable(_BackPointer_A, "backpointer_11");
688    ccV.add( ByteCode.make_aload    (cell[0][0]));
689    ccV.add( ByteCode.make_getfield ( _Cell_backpointer));
690    ccV.add( ByteCode.make_astore   (backpointer[0][0]));
691    ccV.add( ByteCode.make_aload    (cell[0][1]));
692    ccV.add( ByteCode.make_getfield ( _Cell_backpointer));
693    ccV.add( ByteCode.make_astore   (backpointer[0][1]));
694    ccV.add( ByteCode.make_aload    (cell[1][0]));
695    ccV.add( ByteCode.make_getfield ( _Cell_backpointer));
696    ccV.add( ByteCode.make_astore   (backpointer[1][0]));
697    ccV.add( ByteCode.make_aload    (cell[1][1]));
698    ccV.add( ByteCode.make_getfield ( _Cell_backpointer));
699    ccV.add( ByteCode.make_astore   (backpointer[1][1]));
700
701    LocalVariable emissions = new LocalVariable(_double_A, "emissions");
702    ccV.add( ByteCode.make_aload    (cell[0][0] ));
703    ccV.add( ByteCode.make_getfield (_Cell_emissions));
704    ccV.add( ByteCode.make_astore   (emissions));
705
706    LocalVariable max = new LocalVariable(CodeUtils.TYPE_DOUBLE, "max");
707    LocalVariable max_j = new LocalVariable(CodeUtils.TYPE_INT, "max_j");
708    for(int i = 0; i < states.length; i++) {
709      State state = states[i];
710      InstructionVector stateV = new InstructionVector();
711      if(isInit && state instanceof EmissionState) {
712        stateV.add( ByteCode.make_aload   (score[0][0]));
713        stateV.add( ByteCode.make_iconst  (i));
714        if(state instanceof MagicalState) {
715          stateV.add( ByteCode.make_dconst   (0.0));
716          stateV.add( ByteCode.make_aload    (backpointer[0][0]));
717          stateV.add( ByteCode.make_iconst   (i));
718          stateV.add( ByteCode.make_aload    (method.getThis()));
719          stateV.add( ByteCode.make_getfield (terminalBP));
720          stateV.add( ByteCode.make_aastore  ());
721        } else {
722          stateV.add( ByteCode.make_dconst   (Double.NaN));
723        }
724        stateV.add( ByteCode.make_dastore ());
725      } else {
726        int[] advance = getAdvance(state);
727        FiniteAlphabet trans = model.transitionsFrom(state);
728
729        // find max/argmax of t_j[i] + v[j]
730        // make a max pipeline
731        Iterator each_j = trans.iterator();
732        State state_j;
733        int state_jIndx;
734
735        // first state primes the pump
736        stateV.add( ByteCode.make_dconst (Double.NEGATIVE_INFINITY));
737        stateV.add( ByteCode.make_dstore (max));
738        stateV.add( ByteCode.make_iconst (-1));
739        stateV.add( ByteCode.make_istore (max_j));
740
741        // then process each state
742        while(each_j.hasNext()) {
743          state_j = (State) each_j.next();
744          state_jIndx = stateIndex.indexForSymbol(state_j);
745          stateV.add( createTransitionLastSum(
746            method,
747            transitionIndexers[state_jIndx].indexForSymbol(state),
748            state_jIndx,
749            transitionFields,
750            getAdvanced(score, advance)
751          ));
752          stateV.add( ByteCode.make_dup2  ());
753          stateV.add( ByteCode.make_dload (max));
754          stateV.add( ByteCode.make_dcmpl ());
755
756          // if dcmpl is 1, we need to store the new max & imax. If either
757          // is NaN, keep the current max.
758          InstructionVector saveNewMax = new InstructionVector();
759          saveNewMax.add( ByteCode.make_dstore (max));
760          saveNewMax.add( ByteCode.make_iconst (state_jIndx));
761          saveNewMax.add( ByteCode.make_istore (max_j));
762
763          // if they are equal or max is greater or either is NaN
764          // dump current value
765          InstructionVector useOldMax = new InstructionVector();
766          useOldMax.add( ByteCode.make_pop2());
767
768          stateV.add( new IfExpression(
769            ByteCode.op_ifge, // branch if int on stack is >= 0
770            saveNewMax,
771            useOldMax
772          ));
773        }
774
775        // if (max_j == -1)
776        //   score[i] = NaN
777        //   bp[i] = null
778        // else
779        //   sum = emissions[i] + max
780        //   score[i] = sum
781        //   bp[i] = new BackPointer(state[i], bp[adv_0][adv_1], sum)
782        // endif
783
784        // (max == max) && (max_j != -1)
785        stateV.add( ByteCode.make_iload  (max_j));
786
787        InstructionVector ifNoIn = new InstructionVector();
788        InstructionVector ifGotIn = new InstructionVector();
789
790        ifNoIn.add( ByteCode.make_aload       (score[0][0]));
791        ifNoIn.add( ByteCode.make_iconst      (i));
792        ifNoIn.add( ByteCode.make_dconst      (Double.NaN));
793        ifNoIn.add( ByteCode.make_dastore     ());
794        ifNoIn.add( ByteCode.make_aload       (backpointer[0][0]));
795        ifNoIn.add( ByteCode.make_iconst      (i));
796        ifNoIn.add( ByteCode.make_aconst_null ());
797        ifNoIn.add( ByteCode.make_aastore     ());
798
799        // score[i] = emissions[i] + max if emitting state, else score[i] = max
800        ifGotIn.add( ByteCode.make_aload   (score[0][0]));
801        ifGotIn.add( ByteCode.make_iconst  (i));
802        ifGotIn.add( ByteCode.make_dload   (max));
803        if(state instanceof EmissionState) {
804          ifGotIn.add( ByteCode.make_aload   (emissions));
805          ifGotIn.add( ByteCode.make_iconst  (i));
806          ifGotIn.add( ByteCode.make_daload  ());
807          ifGotIn.add( ByteCode.make_dadd    ());
808        }
809        ifGotIn.add( ByteCode.make_dastore ());
810
811        // backpointer[i] = new BackPointer(
812        //  state[i],
813        //  backPointer[adv_0][adv_1],
814        //  score
815        // );
816
817        // backpointer[i] =
818        ifGotIn.add( ByteCode.make_aload    (backpointer[0][0]));
819        ifGotIn.add( ByteCode.make_iconst   (i));
820
821        // new BackPointer - dup for <init> invoke
822        ifGotIn.add( ByteCode.make_new (_BackPointer));
823        ifGotIn.add( ByteCode.make_dup ());
824
825        // state[i]
826        ifGotIn.add( ByteCode.make_aload    (method.getThis()));
827        ifGotIn.add( ByteCode.make_getfield (stateF));
828        ifGotIn.add( ByteCode.make_iconst   (i));
829        ifGotIn.add( ByteCode.make_aaload   ());
830
831        // backpointer[adv_0][adv_1] [max_j]
832        ifGotIn.add( ByteCode.make_aload  (getAdvanced(backpointer, advance)));
833        ifGotIn.add( ByteCode.make_iload  (max_j));
834        ifGotIn.add( ByteCode.make_aaload ());
835
836        // score[i]
837        ifGotIn.add( ByteCode.make_aload  (score[0][0]));
838        ifGotIn.add( ByteCode.make_iconst (i));
839        ifGotIn.add( ByteCode.make_daload ());
840
841        // backpointer.<init>
842        ifGotIn.add( ByteCode.make_invokespecial( _BackPointer_init));
843
844        // store backpointer
845        ifGotIn.add( ByteCode.make_aastore ());
846
847        stateV.add( new IfExpression(
848          ByteCode.op_ifge, // ifge means max_j >= 0
849          ifGotIn,
850          ifNoIn
851        ));
852      }
853     ccV.add(stateV);
854    }
855
856    // dump out scores & backpointers
857    /*LocalVariable sc = new LocalVariable(CodeUtils.TYPE_DOUBLE, "score_i");
858    LocalVariable bp = new LocalVariable(_BackPointer, "bp_i");
859    for(int i = 0; i < states.length; i++) {
860      ccV.add( ByteCode.make_aload  (score[0][0]));
861      ccV.add( ByteCode.make_iconst (i));
862      ccV.add( ByteCode.make_daload ());
863      ccV.add( ByteCode.make_dstore (sc));
864
865      ccV.add( ByteCode.make_aload  (backpointer[0][0]));
866      ccV.add( ByteCode.make_iconst (i));
867      ccV.add( ByteCode.make_aaload ());
868      ccV.add( ByteCode.make_astore (bp));
869    }
870    */
871    ccV.add( ByteCode.make_return ());
872
873    return ccV;
874  }
875
876  private CodeGenerator createFRecursion(
877    boolean isInit,
878    MarkovModel model,
879    State[] states,
880    AlphabetIndex stateIndex,
881    CodeField stateF,
882    CodeField [] transitionFields,
883    AlphabetIndex[] transitionIndexers,
884    GeneratedCodeMethod method
885  ) throws
886    NoSuchMethodException,
887    NoSuchFieldException,
888    IllegalSymbolException,
889    CodeException
890  {
891    CodeClass _Cell = IntrospectedCodeClass.forClass(Cell.class);
892    CodeField _Cell_score = _Cell.getFieldByName("scores");
893    CodeField _Cell_emissions = _Cell.getFieldByName("emissions");
894    CodeClass _double_A = IntrospectedCodeClass.forClass(double [].class);
895    CodeClass _Math = IntrospectedCodeClass.forClass(Math.class);
896    CodeMethod _Math_exp = _Math.getMethod("exp", new CodeClass[] { CodeUtils.TYPE_DOUBLE });
897    CodeMethod _Math_log = _Math.getMethod("log", new CodeClass[] { CodeUtils.TYPE_DOUBLE });
898
899    InstructionVector ccV = new InstructionVector();
900
901    ccV.add( debug(message("Retrieving local variables")));
902
903    // if(isInit && state instanceof emission) {
904    //   cell[0][0] = (state == Magical) ? 0.0 : NaN;
905    // } else {
906    //   cell[0][0].score[i] = cell[0][0].emissions[i] +
907    //                         sum_j(cell[adv_i_0][adv_i_1] + t_j[i])
908    // }
909
910    // cell_00 = cell[0][0];
911    // cell_01 = cell[0][1];
912    // cell_10 = cell[1][0];
913    // cell_11 = cell[1][1];
914    LocalVariable[][] cell = new LocalVariable[2][2];
915    cell[0][0] = new LocalVariable(_Cell, "cell_00");
916    cell[0][1] = new LocalVariable(_Cell, "cell_01");
917    cell[1][0] = new LocalVariable(_Cell, "cell_10");
918    cell[1][1] = new LocalVariable(_Cell, "cell_11");
919
920    ccV.add( ByteCode.make_aload  (method.getVariable("cells")));
921    ccV.add( ByteCode.make_dup    ());
922    ccV.add( ByteCode.make_iconst (0));
923    ccV.add( ByteCode.make_aaload ());
924    ccV.add( ByteCode.make_dup    ());
925    ccV.add( ByteCode.make_iconst (0));
926    ccV.add( ByteCode.make_aaload ());
927    ccV.add( ByteCode.make_astore (cell[0][0]));
928    ccV.add( ByteCode.make_iconst (1));
929    ccV.add( ByteCode.make_aaload ());
930    ccV.add( ByteCode.make_astore (cell[0][1]));
931    ccV.add( ByteCode.make_iconst (1));
932    ccV.add( ByteCode.make_aaload ());
933    ccV.add( ByteCode.make_dup    ());
934    ccV.add( ByteCode.make_iconst (0));
935    ccV.add( ByteCode.make_aaload ());
936    ccV.add( ByteCode.make_astore (cell[1][0]));
937    ccV.add( ByteCode.make_iconst (1));
938    ccV.add( ByteCode.make_aaload ());
939    ccV.add( ByteCode.make_astore (cell[1][1]));
940
941    // score_00 = cell[0][0].score;
942    // score_01 = cell[0][1].score;
943    // score_10 = cell[1][0].score;
944    // score_11 = cell[1][1].score;
945
946    LocalVariable[][] score = new LocalVariable[2][2];
947    score[0][0] = new LocalVariable(_double_A, "score_00");
948    score[0][1] = new LocalVariable(_double_A, "score_01");
949    score[1][0] = new LocalVariable(_double_A, "score_10");
950    score[1][1] = new LocalVariable(_double_A, "score_11");
951    ccV.add( ByteCode.make_aload    (cell[0][0]));
952    ccV.add( ByteCode.make_getfield ( _Cell_score));
953    ccV.add( ByteCode.make_astore   (score[0][0]));
954    ccV.add( ByteCode.make_aload    (cell[0][1]));
955    ccV.add( ByteCode.make_getfield ( _Cell_score));
956    ccV.add( ByteCode.make_astore   (score[0][1]));
957    ccV.add( ByteCode.make_aload    (cell[1][0]));
958    ccV.add( ByteCode.make_getfield ( _Cell_score));
959    ccV.add( ByteCode.make_astore   (score[1][0]));
960    ccV.add( ByteCode.make_aload    (cell[1][1]));
961    ccV.add( ByteCode.make_getfield ( _Cell_score));
962    ccV.add( ByteCode.make_astore   (score[1][1]));
963
964    LocalVariable emissions = new LocalVariable(_double_A, "emissions");
965    ccV.add( ByteCode.make_aload    (cell[0][0] ));
966    ccV.add( ByteCode.make_getfield (_Cell_emissions));
967    ccV.add( ByteCode.make_astore   (emissions));
968
969    LocalVariable max = new LocalVariable(CodeUtils.TYPE_DOUBLE, "max");
970    for(int i = 0; i < states.length; i++) {
971      State state = states[i];
972      InstructionVector stateV = new InstructionVector();
973      // we need to push score & i onto the stack so that after finding the sum
974      // we can just push it back into the array
975      stateV.add( ByteCode.make_aload   (score[0][0]));
976      stateV.add( ByteCode.make_iconst  (i));
977      if(isInit && state instanceof EmissionState) {
978        if(state instanceof MagicalState) {
979          stateV.add( ByteCode.make_dconst   (0.0));
980        } else {
981          stateV.add( ByteCode.make_dconst   (Double.NaN));
982        }
983      } else {
984        int[] advance = getAdvance(state);
985        FiniteAlphabet trans = model.transitionsFrom(state);
986
987        LocalVariable j_scores = getAdvanced(score, advance);
988
989        if(trans.size() == 1) {
990          State state_j = (State) trans.iterator().next();
991          int state_jIndx = stateIndex.indexForSymbol(state_j);
992
993          // only one source. F[i] = trans_j[i] + F[j] + e[i]
994          stateV.add( ByteCode.make_aload    (method.getThis()));
995          stateV.add( ByteCode.make_getfield (transitionFields[state_jIndx]));
996          stateV.add( ByteCode.make_iconst   (transitionIndexers[state_jIndx].indexForSymbol(state)));
997          stateV.add( ByteCode.make_daload   ());
998          stateV.add( ByteCode.make_aload    (j_scores));
999          stateV.add( ByteCode.make_iconst   (state_jIndx));
1000          stateV.add( ByteCode.make_daload   ());
1001          stateV.add( ByteCode.make_dadd     ());
1002          if(state instanceof EmissionState) {
1003            stateV.add( ByteCode.make_aload  (emissions));
1004            stateV.add( ByteCode.make_iconst (i));
1005            stateV.add( ByteCode.make_daload ());
1006            stateV.add( ByteCode.make_dadd   ());
1007          }
1008        } else {
1009          // f[i] = emission[i] + log( sum_j [
1010          //   exp( (j_scores[j] - max_j_score) + t_j[i] + e)
1011          // ]) + max_j_score
1012
1013          // find max j_scores
1014          stateV.add( ByteCode.make_dconst (Double.NEGATIVE_INFINITY));
1015          stateV.add( ByteCode.make_dstore (max));
1016
1017          Iterator each_j = trans.iterator();
1018          while(each_j.hasNext()) {
1019            State state_j = (State) each_j.next();
1020            int state_jIndx = stateIndex.indexForSymbol(state_j);
1021            stateV.add( ByteCode.make_aload    (j_scores));
1022            stateV.add( ByteCode.make_iconst   (state_jIndx));
1023            stateV.add( ByteCode.make_daload   ());
1024            stateV.add( ByteCode.make_dup2     ());
1025            stateV.add( ByteCode.make_dload    (max));
1026            stateV.add( ByteCode.make_dcmpl    ()); // puts -1 if max > this one
1027
1028            InstructionVector ifLargerThanMax = new InstructionVector();
1029            ifLargerThanMax.add( ByteCode.make_dstore (max));
1030
1031            InstructionVector ifSmallerThanMax = new InstructionVector();
1032            ifSmallerThanMax.add( ByteCode.make_pop2());
1033
1034            stateV.add( new IfExpression(
1035              ByteCode.op_ifge, // branch if int on stack >= 0
1036              ifLargerThanMax,
1037              ifSmallerThanMax
1038            ));
1039          }
1040
1041          LocalVariable maxDB = new LocalVariable(CodeUtils.TYPE_DOUBLE, "max");
1042          InstructionVector dbi = new InstructionVector();
1043          dbi.add( ByteCode.make_dload (max));
1044          dbi.add( ByteCode.make_dstore (maxDB));
1045          dbi.add( message("Max " + i + " = ", maxDB));
1046          stateV.add( debug(dbi));
1047
1048          // log sum of exponents - prime the sum with zero
1049          stateV.add( ByteCode.make_dconst (0.0));
1050
1051          each_j = trans.iterator();
1052          while(each_j.hasNext()) {
1053            State state_j = (State) each_j.next();
1054            int state_jIndx = stateIndex.indexForSymbol(state_j);
1055
1056            // score
1057            stateV.add( ByteCode.make_aload  (j_scores));
1058            stateV.add( ByteCode.make_iconst (state_jIndx));
1059            stateV.add( ByteCode.make_daload ());
1060
1061            // is score NaN?
1062            stateV.add( ByteCode.make_dup2());
1063            stateV.add( ByteCode.make_dup2());
1064            stateV.add( ByteCode.make_dcmpl());
1065
1066            InstructionVector scoreNotNaN = new InstructionVector();
1067            // load max & subtract it from score
1068            // (j_score - max)
1069            scoreNotNaN.add( ByteCode.make_dload  (max));
1070            scoreNotNaN.add( ByteCode.make_dsub   ());
1071
1072            // exp( (j_score - max) + transition)
1073            scoreNotNaN.add( ByteCode.make_aload        (method.getThis()));
1074            scoreNotNaN.add( ByteCode.make_getfield     (transitionFields[state_jIndx]));
1075            scoreNotNaN.add( ByteCode.make_iconst       (transitionIndexers[state_jIndx].indexForSymbol(state)));
1076            scoreNotNaN.add( ByteCode.make_daload       ());
1077            scoreNotNaN.add( ByteCode.make_dadd         ());
1078            scoreNotNaN.add( ByteCode.make_invokestatic (_Math_exp));
1079
1080            // sum this and current sum
1081            scoreNotNaN.add( ByteCode.make_dadd());
1082
1083            InstructionVector scoreIsNaN = new InstructionVector();
1084            scoreIsNaN.add( ByteCode.make_pop2());
1085
1086            stateV.add( new IfExpression(
1087              ByteCode.op_ifge,
1088              scoreNotNaN,
1089              scoreIsNaN
1090            ));
1091          }
1092
1093          // log sum
1094          stateV.add( ByteCode.make_invokestatic (_Math_log));
1095
1096          if(state instanceof EmissionState) {
1097            // emissions[i]
1098            stateV.add( ByteCode.make_aload    (emissions));
1099            stateV.add( ByteCode.make_iconst   (i));
1100            stateV.add( ByteCode.make_daload   ());
1101
1102            // sum emission with j sum
1103            stateV.add( ByteCode.make_dadd     ());
1104          }
1105
1106          // lastly add on a factor of max - added here for maximum numerical stability
1107          stateV.add( ByteCode.make_dload (max));
1108          stateV.add( ByteCode.make_dadd  ());
1109        }
1110      }
1111      // store score on stack into scores array
1112      stateV.add( ByteCode.make_dastore ());
1113      ccV.add( stateV );
1114    }
1115
1116    // dump out state scores
1117    LocalVariable sc = new LocalVariable(CodeUtils.TYPE_DOUBLE, "score_i");
1118    InstructionVector dbi = new InstructionVector();
1119    for(int i = 0; i < states.length; i++) {
1120      dbi.add( ByteCode.make_aload  (score[0][0]));
1121      dbi.add( ByteCode.make_iconst (i));
1122      dbi.add( ByteCode.make_daload ());
1123      dbi.add( ByteCode.make_dstore (sc));
1124      dbi.add( message("Score " + i + " = ", sc));
1125    }
1126    ccV.add( debug(dbi));
1127
1128    ccV.add( ByteCode.make_return ());
1129
1130    return ccV;
1131  }
1132
1133  private CodeGenerator createBRecursion(
1134    boolean isInit,
1135    MarkovModel model,
1136    State[] states,
1137    AlphabetIndex stateIndex,
1138    CodeField stateF,
1139    CodeField [] transitionFields,
1140    AlphabetIndex[] transitionIndexers,
1141    GeneratedCodeMethod method
1142  ) throws
1143    NoSuchMethodException,
1144    NoSuchFieldException,
1145    IllegalSymbolException,
1146    CodeException
1147  {
1148    CodeClass _Cell = IntrospectedCodeClass.forClass(Cell.class);
1149    CodeField _Cell_score = _Cell.getFieldByName("scores");
1150    CodeField _Cell_emissions = _Cell.getFieldByName("emissions");
1151    CodeClass _double_A = IntrospectedCodeClass.forClass(double [].class);
1152    CodeClass _Math = IntrospectedCodeClass.forClass(Math.class);
1153    CodeMethod _Math_exp = _Math.getMethod("exp", new CodeClass[] { CodeUtils.TYPE_DOUBLE });
1154    CodeMethod _Math_log = _Math.getMethod("log", new CodeClass[] { CodeUtils.TYPE_DOUBLE });
1155
1156    InstructionVector ccV = new InstructionVector();
1157
1158    ccV.add( debug(message("Retrieving local variables")));
1159
1160    // if(isInit && state instanceof emission) {
1161    //   cell[0][0] = (state == Magical) ? 0.0 : NaN;
1162    // } else {
1163    //   cell[0][0].score[i] = cell[0][0].emissions[i] +
1164    //                         sum_j(cell[adv_i_0][adv_i_1] + t_j[i])
1165    // }
1166
1167    // cell_00 = cell[0][0];
1168    // cell_01 = cell[0][1];
1169    // cell_10 = cell[1][0];
1170    // cell_11 = cell[1][1];
1171    LocalVariable[][] cell = new LocalVariable[2][2];
1172    cell[0][0] = new LocalVariable(_Cell, "cell_00");
1173    cell[0][1] = new LocalVariable(_Cell, "cell_01");
1174    cell[1][0] = new LocalVariable(_Cell, "cell_10");
1175    cell[1][1] = new LocalVariable(_Cell, "cell_11");
1176
1177    ccV.add( ByteCode.make_aload  (method.getVariable("cells")));
1178    ccV.add( ByteCode.make_dup    ());
1179    ccV.add( ByteCode.make_iconst (0));
1180    ccV.add( ByteCode.make_aaload ());
1181    ccV.add( ByteCode.make_dup    ());
1182    ccV.add( ByteCode.make_iconst (0));
1183    ccV.add( ByteCode.make_aaload ());
1184    ccV.add( ByteCode.make_astore (cell[0][0]));
1185    ccV.add( ByteCode.make_iconst (1));
1186    ccV.add( ByteCode.make_aaload ());
1187    ccV.add( ByteCode.make_astore (cell[0][1]));
1188    ccV.add( ByteCode.make_iconst (1));
1189    ccV.add( ByteCode.make_aaload ());
1190    ccV.add( ByteCode.make_dup    ());
1191    ccV.add( ByteCode.make_iconst (0));
1192    ccV.add( ByteCode.make_aaload ());
1193    ccV.add( ByteCode.make_astore (cell[1][0]));
1194    ccV.add( ByteCode.make_iconst (1));
1195    ccV.add( ByteCode.make_aaload ());
1196    ccV.add( ByteCode.make_astore (cell[1][1]));
1197
1198    // score_00 = cell[0][0].score;
1199    // score_01 = cell[0][1].score;
1200    // score_10 = cell[1][0].score;
1201    // score_11 = cell[1][1].score;
1202
1203    LocalVariable[][] score = new LocalVariable[2][2];
1204    score[0][0] = new LocalVariable(_double_A, "score_00");
1205    score[0][1] = new LocalVariable(_double_A, "score_01");
1206    score[1][0] = new LocalVariable(_double_A, "score_10");
1207    score[1][1] = new LocalVariable(_double_A, "score_11");
1208    ccV.add( ByteCode.make_aload    (cell[0][0]));
1209    ccV.add( ByteCode.make_getfield ( _Cell_score));
1210    ccV.add( ByteCode.make_astore   (score[0][0]));
1211    ccV.add( ByteCode.make_aload    (cell[0][1]));
1212    ccV.add( ByteCode.make_getfield ( _Cell_score));
1213    ccV.add( ByteCode.make_astore   (score[0][1]));
1214    ccV.add( ByteCode.make_aload    (cell[1][0]));
1215    ccV.add( ByteCode.make_getfield ( _Cell_score));
1216    ccV.add( ByteCode.make_astore   (score[1][0]));
1217    ccV.add( ByteCode.make_aload    (cell[1][1]));
1218    ccV.add( ByteCode.make_getfield ( _Cell_score));
1219    ccV.add( ByteCode.make_astore   (score[1][1]));
1220
1221    LocalVariable[][] emission = new LocalVariable[2][2];
1222    emission[0][1] = new LocalVariable(_double_A, "emission_01");
1223    emission[1][0] = new LocalVariable(_double_A, "emission_10");
1224    emission[1][1] = new LocalVariable(_double_A, "emission_11");
1225    ccV.add( ByteCode.make_aload    (cell[0][1] ));
1226    ccV.add( ByteCode.make_getfield (_Cell_emissions));
1227    ccV.add( ByteCode.make_astore   (emission[0][1]));
1228    ccV.add( ByteCode.make_aload    (cell[1][0] ));
1229    ccV.add( ByteCode.make_getfield (_Cell_emissions));
1230    ccV.add( ByteCode.make_astore   (emission[1][0]));
1231    ccV.add( ByteCode.make_aload    (cell[1][1] ));
1232    ccV.add( ByteCode.make_getfield (_Cell_emissions));
1233    ccV.add( ByteCode.make_astore   (emission[1][1]));
1234
1235    LocalVariable max = new LocalVariable(CodeUtils.TYPE_DOUBLE, "max");
1236    for(int i = states.length-1; i >= 0 ; i--) {
1237      State state = states[i];
1238      ccV.add( debug(message("Calculating for state " + i + " " + state.getName())));
1239      InstructionVector stateV = new InstructionVector();
1240      // we need to push score & i onto the stack so that after finding the sum
1241      // we can just push it back into the array
1242      stateV.add( ByteCode.make_aload   (score[0][0]));
1243      stateV.add( ByteCode.make_iconst  (i));
1244      if(isInit && state instanceof EmissionState) {
1245        stateV.add( debug(message("initalizing")));
1246        if(state instanceof MagicalState) {
1247          stateV.add( debug(message("magical")));
1248          stateV.add( ByteCode.make_dconst   (0.0));
1249        } else {
1250          stateV.add( debug(message("mundane")));
1251          stateV.add( ByteCode.make_dconst   (Double.NaN));
1252        }
1253      } else {
1254        FiniteAlphabet trans = model.transitionsFrom(state);
1255
1256        if(trans.size() == 1) {
1257          stateV.add( debug(message("single-source optimization")));
1258
1259          State state_j = (State) trans.iterator().next();
1260          int state_jIndx = stateIndex.indexForSymbol(state_j);
1261
1262          // work out advance
1263          // only one source. B[i] = trans_j[i] + B[j] + e[j]
1264          // only add e[j] if emitting state
1265          int [] advance = getAdvance(state_j);
1266
1267          stateV.add( ByteCode.make_aload    (method.getThis()));
1268          stateV.add( ByteCode.make_getfield (transitionFields[i]));
1269          stateV.add( ByteCode.make_iconst   (transitionIndexers[i].indexForSymbol(state_j)));
1270          stateV.add( ByteCode.make_daload   ());
1271          stateV.add( ByteCode.make_aload    (getAdvanced(score, advance)));
1272          stateV.add( ByteCode.make_iconst   (state_jIndx));
1273          stateV.add( ByteCode.make_daload   ());
1274          stateV.add( ByteCode.make_dadd     ());
1275          if(state_j instanceof EmissionState) {
1276            stateV.add( ByteCode.make_aload  (getAdvanced(emission, advance)));
1277            stateV.add( ByteCode.make_iconst (i));
1278            stateV.add( ByteCode.make_daload ());
1279            stateV.add( ByteCode.make_dadd   ());
1280          }
1281
1282          LocalVariable tmp = new LocalVariable(CodeUtils.TYPE_DOUBLE, "tmp");
1283          InstructionVector dbi = new InstructionVector();
1284          dbi.add( ByteCode.make_dup2());
1285          dbi.add( ByteCode.make_dstore(tmp));
1286          dbi.add( message("got sum of ", tmp));
1287          stateV.add( debug(dbi));
1288
1289        } else {
1290          // B[i] = log( sum_j [
1291          //   exp( (j_scores[j] - max_j_score) + t_j[i] + e[j])
1292          // ]) + max_j_score
1293
1294          stateV.add( debug(message("full recursion")));
1295
1296          // find max j_scores
1297          stateV.add( ByteCode.make_dconst (Double.NEGATIVE_INFINITY));
1298          stateV.add( ByteCode.make_dstore (max));
1299
1300          Iterator each_j = trans.iterator();
1301          while(each_j.hasNext()) {
1302            State state_j = (State) each_j.next();
1303            int state_jIndx = stateIndex.indexForSymbol(state_j);
1304            int[] advance = getAdvance(state_j);
1305
1306            stateV.add( ByteCode.make_aload    (getAdvanced(score, advance)));
1307            stateV.add( ByteCode.make_iconst   (state_jIndx));
1308            stateV.add( ByteCode.make_daload   ());
1309            stateV.add( ByteCode.make_dup2     ());
1310            stateV.add( ByteCode.make_dload    (max));
1311            stateV.add( ByteCode.make_dcmpl    ()); // puts -1 if max > this one
1312
1313            InstructionVector ifLargerThanMax = new InstructionVector();
1314            ifLargerThanMax.add( debug(message("Larger")));
1315            ifLargerThanMax.add( debug(message("  max: ", max)));
1316            ifLargerThanMax.add( ByteCode.make_dstore (max));
1317
1318            InstructionVector ifSmallerThanMax = new InstructionVector();
1319            ifSmallerThanMax.add( debug(message("Smaller")));
1320            ifSmallerThanMax.add( debug(message("  max: ", max)));
1321            ifSmallerThanMax.add( ByteCode.make_pop2 ());
1322
1323            stateV.add( new IfExpression(
1324              ByteCode.op_ifge, // branch if int on stack >= 0
1325              ifLargerThanMax,
1326              ifSmallerThanMax
1327            ));
1328          }
1329
1330          stateV.add( debug(message("Taking out factor ", max)));
1331
1332          // sum logs of exponents - prime sum with zero
1333          stateV.add( ByteCode.make_dconst (0.0));
1334
1335          each_j = trans.iterator();
1336          while(each_j.hasNext()) {
1337            State state_j = (State) each_j.next();
1338            int state_jIndx = stateIndex.indexForSymbol(state_j);
1339            int[] advance = getAdvance(state_j);
1340            // score
1341            stateV.add( ByteCode.make_aload  (getAdvanced(score, advance)));
1342            stateV.add( ByteCode.make_iconst (state_jIndx));
1343            stateV.add( ByteCode.make_daload ());
1344
1345            // is score NaN?
1346            stateV.add( ByteCode.make_dup2());
1347            stateV.add( ByteCode.make_dup2());
1348            stateV.add( ByteCode.make_dcmpl());
1349            // stack now looks like sum, score_j, score_j isNaN
1350            // - boolean popped off during conditional branch leaving
1351            //   sum, score_j
1352
1353            InstructionVector scoreNotNaN = new InstructionVector();
1354            // load max & subtract it from score
1355            scoreNotNaN.add( ByteCode.make_dload  (max));
1356            scoreNotNaN.add( ByteCode.make_dsub   ());
1357            // sum, score_j - max
1358
1359            // (j_score - max) + transition + emission[j]) // only add emission if emiting state
1360            scoreNotNaN.add( ByteCode.make_aload        (method.getThis()));
1361            scoreNotNaN.add( ByteCode.make_getfield     (transitionFields[i]));
1362            scoreNotNaN.add( ByteCode.make_iconst       (transitionIndexers[i].indexForSymbol(state_j)));
1363            scoreNotNaN.add( ByteCode.make_daload       ());
1364            scoreNotNaN.add( ByteCode.make_dadd         ());
1365            if(state_j instanceof EmissionState) {
1366              scoreNotNaN.add( ByteCode.make_aload      (getAdvanced(score, advance)));
1367              scoreNotNaN.add( ByteCode.make_iconst     (state_jIndx));
1368              scoreNotNaN.add( ByteCode.make_daload     ());
1369              scoreNotNaN.add( ByteCode.make_dadd       ());
1370            }
1371            scoreNotNaN.add( ByteCode.make_invokestatic (_Math_exp));
1372
1373            // sum this and current sum
1374            scoreNotNaN.add( ByteCode.make_dadd());
1375
1376            InstructionVector scoreIsNaN = new InstructionVector();
1377            scoreIsNaN.add( ByteCode.make_pop2());
1378
1379            stateV.add( new IfExpression(
1380              ByteCode.op_ifge,
1381              scoreNotNaN,
1382              scoreIsNaN
1383            ));
1384          }
1385
1386          // log sum
1387          stateV.add( ByteCode.make_invokestatic (_Math_log));
1388
1389          // lastly add on a factor of max - added here for maximum numerical stability
1390          stateV.add( ByteCode.make_dload (max));
1391          stateV.add( ByteCode.make_dadd  ());
1392        }
1393      }
1394      // store score on stack into scores array
1395      stateV.add( ByteCode.make_dastore ());
1396      ccV.add( stateV );
1397    }
1398
1399    // dump out state scores
1400    LocalVariable sc = new LocalVariable(CodeUtils.TYPE_DOUBLE, "score_i");
1401    InstructionVector dbi = new InstructionVector();
1402    for(int i = 0; i < states.length; i++) {
1403      dbi.add( ByteCode.make_aload  (score[0][0]));
1404      dbi.add( ByteCode.make_iconst (i));
1405      dbi.add( ByteCode.make_daload ());
1406      dbi.add( ByteCode.make_dstore (sc));
1407      dbi.add( message("Score " + i + " = ", sc));
1408    }
1409    ccV.add( debug(dbi));
1410
1411    ccV.add( ByteCode.make_return ());
1412
1413    return ccV;
1414  }
1415
1416  private CodeGenerator createInit(
1417    MarkovModel model, State[] states,
1418    GeneratedCodeClass clazz,
1419    GeneratedCodeMethod __init,
1420    AlphabetIndex[] transitionIndexers,
1421    CodeField[] transitionFields,
1422    CodeField stateF,
1423    CodeField terminalBP
1424  ) throws
1425    NoSuchFieldException, NoSuchMethodException, CodeException,
1426    IllegalSymbolException, BioException
1427  {
1428      CodeClass _Object = IntrospectedCodeClass.forClass(Object.class);
1429      CodeMethod _Object_init = _Object.getConstructor(CodeUtils.EMPTY_LIST);
1430      CodeClass _Symbol = IntrospectedCodeClass.forClass(Symbol.class);
1431      CodeClass _State = IntrospectedCodeClass.forClass(State.class);
1432      CodeClass _State_A = IntrospectedCodeClass.forClass(State [].class);
1433      CodeClass _double_A = IntrospectedCodeClass.forClass(double [].class);
1434      CodeClass _DP = IntrospectedCodeClass.forClass(DP.class);
1435      CodeMethod _DP_getStates = _DP.getMethod("getStates", CodeUtils.EMPTY_LIST);
1436      CodeMethod _DP_getModel = _DP.getMethod("getModel", CodeUtils.EMPTY_LIST);
1437      CodeClass _Distribution = IntrospectedCodeClass.forClass(Distribution.class);
1438      CodeMethod _Distribution_getAlphabet = _Distribution.getMethod("getAlphabet", CodeUtils.EMPTY_LIST);
1439      CodeClass _ScoreType = IntrospectedCodeClass.forClass(ScoreType.class);
1440      CodeMethod _ScoreType_calculateScore = _ScoreType.getMethod("calculateScore", new CodeClass[] {_Distribution, _Symbol});
1441      CodeClass _MarkovModel = IntrospectedCodeClass.forClass(MarkovModel.class);
1442      CodeMethod _MarkovModel_getWeights = _MarkovModel.getMethod("getWeights", new CodeClass[] {_State});
1443      CodeClass _FiniteAlphabet = IntrospectedCodeClass.forClass(FiniteAlphabet.class);
1444      CodeMethod _FiniteAlphabet_size = _FiniteAlphabet.getMethod("size", CodeUtils.EMPTY_LIST);
1445      CodeClass _Math = IntrospectedCodeClass.forClass(Math.class);
1446      CodeMethod _Math_log = _Math.getMethod("log", new CodeClass[] { CodeUtils.TYPE_DOUBLE });
1447
1448      int[] indexToFieldIndex = new int[states.length];
1449      Map distToIndx = new HashMap();
1450      for(int i = 0; i < states.length; i++) {
1451        State s = states[i];
1452        Distribution dist = model.getWeights(s);
1453        Integer indxI = (Integer) distToIndx.get(dist);
1454        if(indxI == null) {
1455          indxI = new Integer(i);
1456          distToIndx.put(dist, indxI);
1457          transitionFields[i] = clazz.createField(
1458            "t_" + i,
1459            _double_A,
1460            CodeUtils.ACC_PROTECTED
1461          );
1462          indexToFieldIndex[i] = i;
1463        } else {
1464          int indx = indxI.intValue();
1465          transitionFields[i] = transitionFields[indx];
1466          indexToFieldIndex[i] = indexToFieldIndex[indx];
1467        }
1468      }
1469
1470      InstructionVector initG = new InstructionVector();
1471      // invoke super()
1472      initG.add( ByteCode.make_aload         (__init.getThis()));
1473      initG.add( ByteCode.make_invokespecial (_Object_init));
1474
1475      // load up the dp object.
1476      // Store the states array, and HMM
1477      LocalVariable statesLV = new LocalVariable(_State_A, "states");
1478      LocalVariable modelLV = new LocalVariable(_MarkovModel, "model");
1479      initG.add( ByteCode.make_aload         (__init.getVariable("dp")));
1480      initG.add( ByteCode.make_dup           ());
1481      initG.add( ByteCode.make_invokevirtual (_DP_getStates));
1482      initG.add( ByteCode.make_astore        (statesLV));
1483      initG.add( ByteCode.make_invokevirtual (_DP_getModel));
1484      initG.add( ByteCode.make_astore        (modelLV));
1485      initG.add( ByteCode.make_aload         (__init.getThis()));
1486      initG.add( ByteCode.make_aload         (statesLV));
1487      initG.add( ByteCode.make_putfield      (stateF));
1488
1489      // store the backPointer thing in terminalBP
1490      if(terminalBP != null) {
1491        initG.add( ByteCode.make_aload    (__init.getThis()));
1492        initG.add( ByteCode.make_aload    (__init.getVariable("backPointer")));
1493        initG.add( ByteCode.make_putfield (terminalBP));
1494      }
1495
1496      LocalVariable distLV = new LocalVariable(_Distribution, "dist");
1497
1498      // load in the transition probabilities to the transition fields
1499      for(int i = 0; i < transitionFields.length; i++) {
1500        // if this field reference is the first one for this distribution
1501        if(indexToFieldIndex[i] == i) {
1502          // Distribution dist = model.getWeights(states[i]);
1503          Distribution dist = model.getWeights(states[i]);
1504
1505          initG.add( ByteCode.make_aload           (modelLV));
1506          initG.add( ByteCode.make_aload           (statesLV));
1507          initG.add( ByteCode.make_iconst          (i));
1508          initG.add( ByteCode.make_aaload          ());
1509          initG.add( ByteCode.make_invokeinterface (_MarkovModel_getWeights));
1510          initG.add( ByteCode.make_astore          (distLV));
1511
1512          int size = ((FiniteAlphabet) dist.getAlphabet()).size();
1513          Symbol[] transitionSymbols = new Symbol[size];
1514
1515          initG.add( ByteCode.make_aload           (distLV));
1516          initG.add( ByteCode.make_invokeinterface (_Distribution_getAlphabet));
1517          initG.add( ByteCode.make_invokeinterface (_FiniteAlphabet_size));
1518
1519          // t_i = new double[size]; // leave t_i on stack
1520          initG.add( ByteCode.make_iconst     (size));
1521          initG.add( ByteCode.make_newarray   (CodeUtils.TYPE_DOUBLE));
1522          initG.add( ByteCode.make_dup        ());
1523          initG.add( ByteCode.make_aload      (__init.getThis()));
1524          initG.add( ByteCode.make_swap       ());
1525          initG.add( ByteCode.make_putfield   (transitionFields[i]));
1526
1527          // t_i[j] = scoreType.calculateScore(
1528          //            dist, states[ jj ]
1529          //          );
1530          // for each jj in dist - j is index from 0 in t_i in same order as jj
1531          int j = 0;
1532          for(int jj = 0; jj < states.length; jj++) {
1533            State state = states[jj];
1534            if(dist.getAlphabet().contains(state)) {
1535              transitionSymbols[j] = state;
1536              initG.add( ByteCode.make_dup             ());
1537              initG.add( ByteCode.make_iconst          (j));
1538              initG.add( ByteCode.make_aload           (__init.getVariable("scoreType")));
1539              initG.add( ByteCode.make_aload           (distLV));
1540              initG.add( ByteCode.make_aload           (statesLV));
1541              initG.add( ByteCode.make_iconst          (jj));
1542              initG.add( ByteCode.make_aaload          ());
1543              initG.add( ByteCode.make_invokeinterface (_ScoreType_calculateScore));
1544              initG.add( ByteCode.make_invokestatic    (_Math_log));
1545              initG.add( ByteCode.make_dastore         ());
1546              j++;
1547            }
1548          }
1549
1550          transitionIndexers[i] = AlphabetManager.getAlphabetIndex(transitionSymbols);
1551          initG.add( ByteCode.make_pop ());
1552        }
1553      }
1554
1555      // return nothing
1556      initG.add( ByteCode.make_return        ());
1557
1558      return initG;
1559  }
1560
1561  private InstructionVector createTransitionLastSum(
1562    GeneratedCodeMethod method,
1563    int i, int j,
1564    CodeField transition[], LocalVariable lastScore
1565  ) throws CodeException {
1566    InstructionVector sumV = new InstructionVector();
1567
1568    // transition_j[i];
1569    sumV.add( ByteCode.make_aload    (method.getThis()));
1570    sumV.add( ByteCode.make_getfield (transition[j]));
1571    sumV.add( ByteCode.make_iconst   (i));
1572    sumV.add( ByteCode.make_daload   ());
1573
1574    // lastScore[j]
1575    sumV.add( ByteCode.make_aload  (lastScore));
1576    sumV.add( ByteCode.make_iconst (j));
1577    sumV.add( ByteCode.make_daload  ());
1578
1579    // add
1580    sumV.add( ByteCode.make_dadd   ());
1581
1582    return sumV;
1583  }
1584
1585  private CodeGenerator message(String message) {
1586    try {
1587      CodeClass _String = IntrospectedCodeClass.forClass(String.class);
1588      CodeClass _System = IntrospectedCodeClass.forClass(System.class);
1589      CodeField _System_out = _System.getFieldByName("out");
1590      CodeClass _PrintStream = IntrospectedCodeClass.forClass(PrintStream.class);
1591      CodeMethod _PrintStream_println = _PrintStream.getMethod("println", new CodeClass[] { _String });
1592
1593      InstructionVector iv = new InstructionVector();
1594
1595      iv.add( ByteCode.make_getstatic     (_System_out));
1596      iv.add( ByteCode.make_sconst        (message));
1597      iv.add( ByteCode.make_invokevirtual (_PrintStream_println));
1598
1599      return iv;
1600    } catch (NoSuchFieldException nsfe) {
1601      throw new BioError( "Can't make message statements", nsfe);
1602    } catch (NoSuchMethodException nsme) {
1603      throw new BioError( "Can't make message statements", nsme);
1604    }
1605  }
1606
1607  private CodeGenerator message(String message, LocalVariable var) {
1608    try {
1609      CodeClass _Object = IntrospectedCodeClass.forClass(Object.class);
1610      CodeClass _String = IntrospectedCodeClass.forClass(String.class);
1611      CodeClass _System = IntrospectedCodeClass.forClass(System.class);
1612      CodeField _System_out = _System.getFieldByName("out");
1613      CodeClass _PrintStream = IntrospectedCodeClass.forClass(PrintStream.class);
1614      CodeMethod _PrintStream_print = _PrintStream.getMethod("print", new CodeClass[] { _String });
1615
1616      InstructionVector iv = new InstructionVector();
1617
1618      iv.add( ByteCode.make_getstatic     (_System_out));
1619      iv.add( ByteCode.make_sconst        (message));
1620      iv.add( ByteCode.make_invokevirtual (_PrintStream_print));
1621
1622      iv.add( ByteCode.make_getstatic     (_System_out));
1623
1624      CodeMethod _PrintStream_printXln;
1625      if(var.getType().isPrimitive()) {
1626        _PrintStream_printXln = _PrintStream.getMethod("println", new CodeClass[] { var.getType() });
1627        if(var.getType() == CodeUtils.TYPE_INT) {
1628          iv.add( ByteCode.make_iload(var));
1629        } else if(var.getType() == CodeUtils.TYPE_DOUBLE) {
1630          iv.add( ByteCode.make_dload(var));
1631        } else {
1632          throw new BioError("Unsupported primative " + var.getType());
1633        }
1634      } else {
1635        iv.add( ByteCode.make_aload(var));
1636        _PrintStream_printXln = _PrintStream.getMethod("println", new CodeClass [] { _Object });
1637      }
1638      iv.add( ByteCode.make_invokevirtual (_PrintStream_printXln));
1639
1640      return iv;
1641    } catch (NoSuchFieldException nsfe) {
1642      throw new BioError( "Can't make message statements", nsfe);
1643    } catch (NoSuchMethodException nsme) {
1644      throw new BioError( "Can't make message statements", nsme);
1645    } catch (CodeException ce) {
1646      throw new BioError( "Can't make message statements", ce);
1647    }
1648  }
1649
1650  private CodeGenerator debug(CodeGenerator child) {
1651    if(debug) {
1652      return child;
1653    } else {
1654      return CodeUtils.DO_NOTHING;
1655    }
1656  }
1657
1658  private int[] getAdvance(State s) {
1659    if(s instanceof EmissionState) {
1660      return ((EmissionState) s).getAdvance();
1661    } else {
1662      return new int[] {0, 0};
1663    }
1664  }
1665
1666  private LocalVariable getAdvanced(LocalVariable[][] what, int[] advance) {
1667    return what[advance[0]][advance[1]];
1668  }
1669
1670  private static class Factory implements CellCalculatorFactory {
1671    private final DP dp;
1672    private final Constructor forwards;
1673    private final Constructor backwards;
1674    private final Constructor viterbi;
1675
1676    public Factory(
1677      DP dp,
1678      Constructor forwards,
1679      Constructor backwards,
1680      Constructor viterbi
1681    ) {
1682      this.dp = dp;
1683      this.viterbi = viterbi;
1684      this.forwards = forwards;
1685      this.backwards = backwards;
1686    }
1687
1688    public CellCalculator forwards(ScoreType scoreType)
1689    throws
1690      IllegalSymbolException,
1691      IllegalAlphabetException,
1692      IllegalTransitionException
1693    {
1694      try {
1695        return (CellCalculator) forwards.newInstance(new Object[] { dp, scoreType });
1696      } catch (InstantiationException ie) {
1697        throw new BioError("Counld not instantiate auto-generated class");
1698      } catch (IllegalAccessException ie) {
1699        throw new BioError("Counld not instantiate auto-generated class");
1700      } catch (InvocationTargetException ie) {
1701        throw new BioError("Counld not instantiate auto-generated class");
1702      }
1703    }
1704
1705    public CellCalculator backwards(ScoreType scoreType)
1706    throws
1707      IllegalSymbolException,
1708      IllegalAlphabetException,
1709      IllegalTransitionException
1710    {
1711      try {
1712        return (CellCalculator) backwards.newInstance(new Object[] { dp, scoreType });
1713      } catch (InstantiationException ie) {
1714        throw new BioError("Counld not instantiate auto-generated class");
1715      } catch (IllegalAccessException ie) {
1716        throw new BioError("Counld not instantiate auto-generated class");
1717      } catch (InvocationTargetException ie) {
1718        throw new BioError("Counld not instantiate auto-generated class");
1719      }
1720    }
1721
1722    public CellCalculator viterbi(ScoreType scoreType, BackPointer terminal)
1723    throws
1724      IllegalSymbolException,
1725      IllegalAlphabetException,
1726      IllegalTransitionException
1727    {
1728      try {
1729        return (CellCalculator) viterbi.newInstance(new Object[] { dp, scoreType, terminal });
1730      } catch (InstantiationException ie) {
1731        throw new BioError( "Counld not instantiate auto-generated class", ie);
1732      } catch (IllegalAccessException ie) {
1733        throw new BioError( "Counld not instantiate auto-generated class-", ie);
1734      } catch (InvocationTargetException ie) {
1735        throw new BioError("Counld not instantiate auto-generated class using " + viterbi + " with " + dp + ", " + scoreType + ", " + terminal, ie);
1736      }
1737    }
1738  }
1739}