@Override
	public void runMStep() {
		
		Set<String> semanticWords = this.mtModule.getSemanticWords();
		Set<String> naturalWords = this.mtModule.getNaturalWords();
		
		WordParam wp = this.mtModule.getWp();
		DistortionParam dp = this.mtModule.getDp();
		
		int maxNatural = this.mtModule.getMaxNaturalCommandLength();
		int maxSemantic = this.mtModule.getMaxSemanticCommandLength();
		
		//M-step for word params
		for(String gWord : semanticWords){
			double sc = singleWordCounts.v(gWord);
			for(String pWord : naturalWords){
				double jc = jointWordCounts.v(tokenCombine(pWord, gWord));
				
				double p = jc > 0. ? jc / sc : 0.;
				wp.set(p, pWord, gWord);
				
			}
		}
		
		//M step for distortion params
		for(int m = 1; m <= maxNatural; m++){
			for(int l = 1; l <= maxSemantic; l++){
				
				/* the first two loops are to iterate over all possible text length pairs
				 * the next to loops will be to iterate over all possible assignments for them
				 */
				
				for(int i = 1; i <= m; i++){

					double sc = singleDistortionCounts.v(new IntTupleHash(i, l, m));
					for(int j = 0; j <= l; j++){
						double jc = jointDistortionCounts.v(new IntTupleHash(j, i, l, m));
						
						double p = jc > 0. ? jc / sc : 0.;
						dp.set(p, j, i, l, m);
						
					}
					
				}
				
				
			}
		}
		
		
		
		
		//reset storage for next EM step
		jointWordCounts = new HashedAggregator<String>(wordAdditiveConstant);
		singleWordCounts = new HashedAggregator<String>(wordAdditiveConstant*this.mtModule.getNaturalWords().size());
		
		jointDistortionCounts = new HashedAggregator<IntTupleHash>(0);
		singleDistortionCounts = new HashedAggregator<IntTupleHash>(0);
		
		
		this.numEMIterations++;
		if(this.numEMIterations >= this.numWithWordParamAlone){
			this.factorInAlignment = true;
		}
		
		this.gm.emptyCache();

	}