@Override
    public void train(List<SentencePair> trainingData) {
        System.out.println("NUM ITERS = " + NUM_ITERS);
        
        System.out.println("Starting train() for model 2...");
        
        initParams(trainingData);
        
        for (int p = 0; p < NUM_ITERS; p++) {
            System.out.println("Model 2 iteration " + p);
            
            clearCounts();

            // E-Step
            System.out.println("E-step...");
            for (int k = 0; k < trainingData.size(); k++) {
                SentencePair currDataPoint = trainingData.get(k);
                
                List<String> f = currDataPoint.getSourceWords();
                List<String> e = new ArrayList<String>(currDataPoint.getTargetWords());
                e.add(NULL_WORD);
                
                int m = f.size();
                int l = e.size();
                
                // source
                for (int i = 0; i < m; i++) {
                    String currFWord = f.get(i);
                    
                    // compute the normalization factor for delta
                    double deltaNormalization = 0.0;
                    
                    // target
                    for (int j = 0; j < l; j++) {
                        deltaNormalization += q_jilm(j, i, l, m) * t_fe.getCount(currFWord, e.get(j));
                    }

                    // target
                    for (int j = 0; j < l; j++) {
                        String currEWord = e.get(j);
                        
                        double delta = q_jilm(j, i, l, m) * t_fe.getCount(currFWord, currEWord) / deltaNormalization; 

                        c_ef.incrementCount(currEWord, currFWord, delta);
                        c_e.incrementCount(currEWord, delta);

                        String ilm = convertIntsToStringKey(i, l, m);
                        c_jilm.incrementCount(ilm, j, delta);
                        c_ilm.incrementCount(ilm, delta);
                    }
                }
            }

            // M-Step
            t_fe = new CounterMap<String, String>();
            q_jilm = new CounterMap<String, Integer>();
            System.out.println("M-step...");
            for (String e : c_ef.keySet()) {
                for (String f : c_ef.getCounter(e).keySet()) {
                    t_fe.setCount(f, e, c_ef.getCount(e, f) / c_e.getCount(e));
                }
            }

            for (String ilm : c_jilm.keySet()) {
                for (Integer j : c_jilm.getCounter(ilm).keySet()) {
                    q_jilm.setCount(ilm, j, c_jilm.getCount(ilm, j) / c_ilm.getCount(ilm));
                }
            }
        }
        
        System.out.println("Finished train() for Model 2.");
    }