gt: 					if (Math.abs(difference) >= quality) {
context: /**
   * Copyright (C) 2001-2020 by RapidMiner and the contributors
   * 
   * Complete list of developers available at our web site:
   * 
   * http://rapidminer.com
   * 
   * This program is free software: you can redistribute it and/or modify it under the terms of the
   * GNU Affero General Public License as published by the Free Software Foundation, either version 3
   * of the License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
   * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Affero General Public License for more details.
   * 
   * You should have received a copy of the GNU Affero General Public License along with this program.
   * If not, see http://www.gnu.org/licenses/.
  */
  package com.rapidminer.operator.clustering.clusterer.soft;
  
  import java.util.Collection;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Random;
  import java.util.Vector;
  
  import com.rapidminer.example.Attribute;
  import com.rapidminer.example.Example;
  import com.rapidminer.example.ExampleSet;
  import com.rapidminer.example.Statistics;
  import com.rapidminer.example.Tools;
  import com.rapidminer.example.table.AttributeFactory;
  import com.rapidminer.operator.OperatorCreationException;
  import com.rapidminer.operator.OperatorDescription;
  import com.rapidminer.operator.OperatorException;
  import com.rapidminer.operator.OperatorVersion;
  import com.rapidminer.operator.UserError;
  import com.rapidminer.operator.clustering.ClusterModel;
  import com.rapidminer.operator.clustering.FlatFuzzyClusterModel;
  import com.rapidminer.operator.clustering.clusterer.KMeans;
  import com.rapidminer.operator.clustering.clusterer.RMAbstractClusterer;
  import com.rapidminer.operator.ports.metadata.AttributeMetaData;
  import com.rapidminer.parameter.ParameterType;
  import com.rapidminer.parameter.ParameterTypeBoolean;
  import com.rapidminer.parameter.ParameterTypeCategory;
  import com.rapidminer.parameter.ParameterTypeDouble;
  import com.rapidminer.parameter.ParameterTypeInt;
  import com.rapidminer.parameter.UndefinedParameterError;
  import com.rapidminer.parameter.conditions.AboveOperatorVersionCondition;
  import com.rapidminer.parameter.conditions.EqualTypeCondition;
  import com.rapidminer.tools.Ontology;
  import com.rapidminer.tools.OperatorService;
  import com.rapidminer.tools.RandomGenerator;
  import com.rapidminer.tools.math.VectorMath;
  import com.rapidminer.tools.math.similarity.DistanceMeasures;
  
  import Jama.Matrix;
  
  
  /**
   * This operator represents an implementation of the EM-algorithm.
   *
   * @author Regina Fritsch
   */
  public class EMClusterer extends RMAbstractClusterer {
  
  	private static final OperatorVersion BEFORE_MEASURE_PARAM = new OperatorVersion(7, 5, 3);
  
  	/** The parameter name for &quot;the maximal number of clusters&quot; */
  	public static final String PARAMETER_K = "k";
  
  	/**
  	 * The parameter name for &quot;the maximal number of runs of the k method with random
  	 * initialization that are performed&quot;
  	 */
  	public static final String PARAMETER_MAX_RUNS = "max_runs";
  
  	/**
  	 * The parameter name for &quot;the maximal number of iterations performed for one run of the k
  	 * method&quot;
  	 */
  	public static final String PARAMETER_MAX_OPTIMIZATION_STEPS = "max_optimization_steps";
  
  	/**
  	 * The parameter name for &quot;the quality, which has to be fulfilled for the stopping of the
  	 * soft clustering&quot;
  	 */
  	public static final String PARAMETER_QUALITY = "quality";
  
  	/**
  	 * The parameter name for &quot;Indicates if the probabilities will be shown in example
  	 * table&quot;
  	 */
  	public static final String PARAMETER_SHOW_PROBABILITIES = "show_probabilities";
  
  	/** The parameter name for &quot;Indicates the initialization distribution&quot; */
  	public static final String PARAMETER_INITIALIZATION_DISTRIBUTION = "inital_distribution";
  
  	/** The parameter name for &quot;List of the different init distributions&quot; */
  	public static final String[] INIT_DISTRIBUTION = { "randomly assigned examples", "k-means run", "average parameters" };
  
  	/** The parameter value for &quot;Init distributions randomly assigned&quot; */
  	public static final int RANDOMLY_ASSIGNED = 0;
  
  	/** The parameter value for &quot;Init distributions hard clustering&quot; */
  	public static final int K_MEANS = 1;
  
  	/** The parameter value for &quot;Init distributions average parameters&quot; */
  	public static final int AVERAGE_PARAMETERS = 2;
  
  	/** The parameter name for &quot;Indicates if the example set has correlated attributes&quot; */
  	public static final String PARAMETER_CORRELATED = "correlated_attributes";
  
  	public EMClusterer(OperatorDescription description) {
  		super(description);
  	}
  
  	@Override
  	protected Collection<AttributeMetaData> getAdditionalAttributes() {
  		List<AttributeMetaData> propAttributes = new LinkedList<AttributeMetaData>();
  		try {
  			int k = getParameterAsInt(PARAMETER_K);
  			for (int i = 0; i < k; i++) {
  				AttributeMetaData newAttr = new AttributeMetaData("cluster_" + i + "_probability", Ontology.REAL,
  						"cluster_" + i + "_probability");
  				propAttributes.add(newAttr);
  			}
  		} catch (UndefinedParameterError e) {
  		}
  		return propAttributes;
  	}
  
  	/*
  	 * Creates the Clustermodel.
  	 */
  	public ClusterModel createClusterModel(ExampleSet exampleSet) throws OperatorException {
  		FlatFuzzyClusterModel bestModel = null;
  
  		int initialMaxRuns = getParameterAsInt(PARAMETER_MAX_RUNS);
  		int maxRuns = initialMaxRuns;
  
  		boolean isCorrelated = getParameterAsBoolean(PARAMETER_CORRELATED);
  		boolean addAsLabel = addsLabelAttribute();
  		boolean removeUnlabeled = getParameterAsBoolean(RMAbstractClusterer.PARAMETER_REMOVE_UNLABELED);
  		double quality = getParameterAsDouble(PARAMETER_QUALITY);
  		int k = getParameterAsInt(PARAMETER_K);
  
  		// init operator progress
  		int maxOptiRuns = getParameterAsInt(PARAMETER_MAX_OPTIMIZATION_STEPS);
  		getProgress().setTotal(100);
  		int progressOffset = 0;
  
  		int initSpecialSize = exampleSet.getAttributes().specialSize();
  		double[][] exampleInClusterProbability = new double[exampleSet.size()][k];
  
  		boolean showProbs = getParameterAsBoolean(PARAMETER_SHOW_PROBABILITIES);
  
  		double max = Double.NEGATIVE_INFINITY;
  		int exceptionCounter = 0;
  
  		int[] bestAssignments = null;
  
  		RandomGenerator randomGenerator = RandomGenerator.getGlobalRandomGenerator();
  
  		// the iterations
  		for (int iter = 0; iter < maxRuns; iter++) {
  			FlatFuzzyClusterModel result = new FlatFuzzyClusterModel(exampleSet, k, addAsLabel, removeUnlabeled);
  			FlatFuzzyClusterModel oldResult = null;
  			// initialize the model
  			try {
  				init(exampleSet, result, k, initSpecialSize, exampleInClusterProbability, showProbs, isCorrelated);
  			} catch (OperatorCreationException e1) {
  				e1.printStackTrace();
  			}
  			boolean stableState = false;
  			double logLikelihoodOld = Double.POSITIVE_INFINITY;
  			double logLikelihood = 0;
  			// the optimization-steps
  			int[] clusterAssignments = new int[exampleSet.size()];
  			try {
  				for (int optiStep = 0; optiStep < maxOptiRuns && !stableState; optiStep++) {
  					getProgress().setCompleted(progressOffset + 100 * (iter * maxOptiRuns + optiStep) / maxRuns / maxOptiRuns);
  					stableState = true;
  					oldResult = result;
  					result = new FlatFuzzyClusterModel(exampleSet, k, addAsLabel, removeUnlabeled);
  					// Compute the probabilities for each example with each cluster
  					if (isCorrelated) {
  						expectationCorrelated(exampleSet, k, exampleInClusterProbability, oldResult);
  					} else {
  						expectationNonCorrelated(exampleSet, k, exampleInClusterProbability, oldResult);
  					}
  					// compute the hard-clustering from the soft-clustering (assignments of the
  					// examples to the clusters)
  					for (int exampleIndex = 0; exampleIndex < exampleSet.size(); exampleIndex++) {
  						int bestIndex = bestIndex(exampleIndex, k, exampleInClusterProbability);
  						if (bestIndex < 0) {
  							bestIndex = randomGenerator.nextInt(result.getNumberOfClusters());
  						}
  						clusterAssignments[exampleIndex] = bestIndex;
  					}
  					result.setClusterAssignments(clusterAssignments, exampleSet);
  					// Recalculate the values: cluster probabilities, means and standard deviations
  					maximization(exampleSet, k, exampleInClusterProbability, result, isCorrelated);
  					// test if the quality of the soft-clustering performs the user-defined quality
  					logLikelihood = computeLogLikelihood(k, exampleInClusterProbability, result);
  					double difference = logLikelihoodOld - logLikelihood;
  