<commit_before>/*
 * This file is part of the PSL software.
 * Copyright 2011-2013 University of Maryland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.umd.cs.psl.application.learning.weight.em;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Iterables;

import edu.umd.cs.psl.application.learning.weight.TrainingMap;
import edu.umd.cs.psl.application.learning.weight.maxlikelihood.VotedPerceptron;
import edu.umd.cs.psl.application.util.Grounding;
import edu.umd.cs.psl.config.ConfigBundle;
import edu.umd.cs.psl.config.ConfigManager;
import edu.umd.cs.psl.database.Database;
import edu.umd.cs.psl.model.Model;
import edu.umd.cs.psl.model.atom.ObservedAtom;
import edu.umd.cs.psl.model.atom.RandomVariableAtom;
import edu.umd.cs.psl.model.kernel.CompatibilityKernel;
import edu.umd.cs.psl.model.kernel.linearconstraint.GroundValueConstraint;
import edu.umd.cs.psl.reasoner.Reasoner;
import edu.umd.cs.psl.reasoner.ReasonerFactory;

/**
 * Abstract superclass for implementations of the expectation-maximization
 * algorithm for learning with latent variables.
 * <p>
 * This class extends {@link VotedPerceptron}, which is used during the M-step
 * to update the weights.
 * 
 * @author <NAME> <<EMAIL>>
 */
abstract public class ExpectationMaximization extends VotedPerceptron {

	private static final Logger log = LoggerFactory.getLogger(ExpectationMaximization.class);
	
	/**
	 * Prefix of property keys used by this class.
	 * 
	 * @see ConfigManager
	 */
	public static final String CONFIG_PREFIX = "em";
	
	/**
	 * Key for positive int property for the number of iterations of expectation
	 * maximization to perform
	 */
	public static final String ITER_KEY = CONFIG_PREFIX + ".iterations";
	/** Default value for ITER_KEY property */
	public static final int ITER_DEFAULT = 10;
	
	/**
	 * Key for positive double property for the minimum absolute change in weights
	 * such that EM is considered converged
	 */
	public static final String TOLERANCE_KEY = CONFIG_PREFIX + ".tolerance";
	/** Default value for TOLERANCE_KEY property */
	public static final double TOLERANCE_DEFAULT = 1e-3;
	
	protected final int iterations;
	protected final double tolerance;
	
	private int round;
	
	/**
	 * A reasoner for inferring the latent variables conditioned on
	 * the observations and labels
	 */
	protected Reasoner latentVariableReasoner;
	
	protected List<CompatibilityKernel> kernels;
	protected double [] weights;
	
	public ExpectationMaximization(Model model, Database rvDB,
			Database observedDB, ConfigBundle config) {
		super(model, rvDB, observedDB, config);

		iterations = config.getInt(ITER_KEY, ITER_DEFAULT);

		tolerance = config.getDouble(TOLERANCE_KEY, TOLERANCE_DEFAULT);
		
		kernels = new ArrayList<CompatibilityKernel>();
		
		for (CompatibilityKernel k : Iterables.filter(model.getKernels(), CompatibilityKernel.class))
			kernels.add(k);
		weights = new double[kernels.size()];
		for (int i = 0; i < weights.length; i++)
			weights[i] = Double.POSITIVE_INFINITY;
		
		latentVariableReasoner = null;
	}

	@Override
	protected void doLearn() {
		round = 0;
		while (round++ < iterations) {
			log.debug("Beginning EM round {} of {}", round, iterations);
			/* E-step */
			minimizeKLDivergence();
			/* M-step */
			super.doLearn();
			
			double change = 0;
			for (int i = 0; i < kernels.size(); i++) {
				change += Math.pow(weights[i] - kernels.get(i).getWeight().getWeight(), 2);
				weights[i] = kernels.get(i).getWeight().getWeight();
			}
			
			double loss = getLoss();
			
			change = Math.sqrt(change);
			if (change <= tolerance) {
				log.info("EM converged with absolute weight change {} in {} rounds. Loss: " + loss, change, round);
				break;
			} else
				log.info("Finished EM round {} with change {}. Loss: " + loss, round, change);
		}
	}<commit_msg>Fixed superclass member hiding bug.<commit_after>/*
 * This file is part of the PSL software.
 * Copyright 2011-2013 University of Maryland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.umd.cs.psl.application.learning.weight.em;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.umd.cs.psl.application.learning.weight.TrainingMap;
import edu.umd.cs.psl.application.learning.weight.maxlikelihood.VotedPerceptron;
import edu.umd.cs.psl.application.util.Grounding;
import edu.umd.cs.psl.config.ConfigBundle;
import edu.umd.cs.psl.config.ConfigManager;
import edu.umd.cs.psl.database.Database;
import edu.umd.cs.psl.model.Model;
import edu.umd.cs.psl.model.atom.ObservedAtom;
import edu.umd.cs.psl.model.atom.RandomVariableAtom;
import edu.umd.cs.psl.model.kernel.linearconstraint.GroundValueConstraint;
import edu.umd.cs.psl.reasoner.Reasoner;
import edu.umd.cs.psl.reasoner.ReasonerFactory;

/**
 * Abstract superclass for implementations of the expectation-maximization
 * algorithm for learning with latent variables.
 * <p>
 * This class extends {@link VotedPerceptron}, which is used during the M-step
 * to update the weights.
 * 
 * @author <NAME> <<EMAIL>>
 */
abstract public class ExpectationMaximization extends VotedPerceptron {

	private static final Logger log = LoggerFactory.getLogger(ExpectationMaximization.class);
	
	/**
	 * Prefix of property keys used by this class.
	 * 
	 * @see ConfigManager
	 */
	public static final String CONFIG_PREFIX = "em";
	
	/**
	 * Key for positive int property for the number of iterations of expectation
	 * maximization to perform
	 */
	public static final String ITER_KEY = CONFIG_PREFIX + ".iterations";
	/** Default value for ITER_KEY property */
	public static final int ITER_DEFAULT = 10;
	
	/**
	 * Key for positive double property for the minimum absolute change in weights
	 * such that EM is considered converged
	 */
	public static final String TOLERANCE_KEY = CONFIG_PREFIX + ".tolerance";
	/** Default value for TOLERANCE_KEY property */
	public static final double TOLERANCE_DEFAULT = 1e-3;
	
	protected final int iterations;
	protected final double tolerance;
	
	private int round;
	
	/**
	 * A reasoner for inferring the latent variables conditioned on
	 * the observations and labels
	 */
	protected Reasoner latentVariableReasoner;
	
	public ExpectationMaximization(Model model, Database rvDB,
			Database observedDB, ConfigBundle config) {
		super(model, rvDB, observedDB, config);

		iterations = config.getInt(ITER_KEY, ITER_DEFAULT);

		tolerance = config.getDouble(TOLERANCE_KEY, TOLERANCE_DEFAULT);
		
		latentVariableReasoner = null;
	}

	@Override
	protected void doLearn() {
		double[] weights = new double[kernels.size()];
		for (int i = 0; i < weights.length; i++)
			weights[i] = Double.POSITIVE_INFINITY;
		
		round = 0;
		while (round++ < iterations) {
			log.debug("Beginning EM round {} of {}", round, iterations);
			/* E-step */
			minimizeKLDivergence();
			/* M-step */
			super.doLearn();
			
			double change = 0;
			for (int i = 0; i < kernels.size(); i++) {
				change += Math.pow(weights[i] - kernels.get(i).getWeight().getWeight(), 2);
				weights[i] = kernels.get(i).getWeight().getWeight();
			}
			
			double loss = getLoss();
			
			change = Math.sqrt(change);
			if (change <= tolerance) {
				log.info("EM converged with absolute weight change {} in {} rounds. Loss: " + loss, change, round);
				break;
			} else
				log.info("Finished EM round {} with change {}. Loss: " + loss, round, change);
		}
	}
{'fraction_non_alphanumeric': 0.1072310405643739, 'fraction_numerical': 0.005408583186360964, 'mean_word_length': 4.00942285041225, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2659182', 'n_tokens_mistral': 2845, 'n_tokens_neox': 2540, 'n_words': 786}