@Override
    public void trainWord(String word,
            Value<State> times,
            HashMap<State, Value<Character>> restart) {
        int len = word.length();
        double wordProb;
        Value<State> alpha = initial(1.0);
        Value<State> beta;
        ArrayList<Value<State>> alphas = new ArrayList<Value<State>>();

        alphas.add(alpha); //System.out.println("alpha(0)= \n" + alpha);
        for (int t = 0; t < len; ++t) {
            Character c = word.charAt(t);
            alpha = forward(alpha, c); //System.out.println("alpha(" + (t+1) + ")= \n" + alpha);
            alphas.add(alpha);
        }
        beta = initial(1.0);
        wordProb = alpha.get(I);//System.out.println("wordProb="+wordProb); //print();
        for (int t = len - 1; t >= 0; --t) {
            Character c = word.charAt(t);   // System.out.println("beta(" + (t+1) + ")= \n" + beta);
            alpha = alphas.get(t);
            for (State i : alpha.keySet()) {
                double alphai = alpha.get(i);
                State j = i.next(c);
                double restartValue = beta.containsKey(I) ? clip(alphai * i.prRestart(c) * beta.get(I) / wordProb) : 0;
                if (j != null && beta.containsKey(j)) {
                    double nextValue =
                            clip(alphai * i.prNext(c) * beta.get(j) / wordProb);  //System.out.println(i+"->"+j+"("+beta.get(j)+")");
                    times.addValue(j, nextValue); //System.out.println(j + " addTimes = " + nextValue);
                }
                restart.get(i).addValue(c, restartValue); //System.out.println(i + " addRestart["+c+"]=" + restartValue);
                times.addValue(I, restartValue);
            }
            if (t > 0) {  // compute new beta
                Value<State> output = new Value<State>();
                for (State i : alpha.keySet()) {
                    State j = i.next(c);
                    if (j != null) {
                        output.addValue(i, beta.getValue(j) * i.prNext(c));
                    }
                    output.addValue(i, beta.getValue(I) * i.prRestart(c));
                }
                beta = output;
            }
        }
    }