Commits

muzny  committed 57cc56c

More succinct structure

  • Participants
  • Parent commits 1fb1363

Comments (0)

Files changed (142)

File WiktionaryFileIO/.gitignore

+/bin

File WiktionaryIdiomClassification/.gitignore

+/bin

File WiktionaryIdiomDetection/bin/.project

+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>WiktionaryIdiomDetection</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

File WiktionaryIdioms/.classpath

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="lib" path="lib/ant-1.7.1.jar"/>
+	<classpathentry kind="lib" path="lib/ant-launcher-1.7.1.jar"/>
+	<classpathentry kind="lib" path="lib/commons-configuration-1.9.jar"/>
+	<classpathentry kind="lib" path="lib/commons-lang-2.6.jar"/>
+	<classpathentry kind="lib" path="lib/commons-lang3-3.1.jar"/>
+	<classpathentry kind="lib" path="lib/de.tudarmstadt.ukp.wikipedia.api-0.9.2.jar"/>
+	<classpathentry kind="lib" path="lib/de.tudarmstadt.ukp.wikipedia.datamachine-0.9.2-jar-with-dependencies.jar"/>
+	<classpathentry kind="lib" path="lib/de.tudarmstadt.ukp.wiktionary-0.16.1.jar"/>
+	<classpathentry kind="lib" path="lib/gson-2.2.2.jar"/>
+	<classpathentry kind="lib" path="lib/jaws-bin.jar"/>
+	<classpathentry kind="lib" path="lib/stanford-corenlp-1.3.5.jar"/>
+	<classpathentry kind="lib" path="lib/timestools.jar"/>
+	<classpathentry kind="lib" path="lib/wikokit-20120611.jar"/>
+	<classpathentry kind="lib" path="lib/xercesImpl-2.9.1-lucene.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

File WiktionaryIdioms/.project

+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>WiktionaryIdioms</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

File WiktionaryIdioms/.settings/org.eclipse.jdt.core.prefs

+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6

File WiktionaryIdioms/bin/.gitignore

+/classifier
+/config
+/detector
+/fileio
+/mysql

File WiktionaryIdioms/config/dbconfig.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<!-- config.xml -->
+<config>
+	<detector>
+		<lookupDb></lookupDb>
+		<dbTable></dbTable>
+	</detector>
+	
+	<SenseFeature>
+		<lookupDb>wiktionary_data_sets</lookupDb>
+	</SenseFeature>
+	
+</config>

File WiktionaryIdioms/config/detectorconfig.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<!-- config.xml -->
+<config>
+	<default>
+		<jwktlPath>/Users/golux/Research/wiktionary_output/</jwktlPath>
+		<database>wiktionary_data_sets</database>
+		<table>example_sentences</table>
+		<column>data_set_classifier</column>
+		<testData>test</testData>
+		<label>corrected_label</label>
+		<classifierModelCorrected>./paperOutputModels/devCorrectedUncleanedAll.model</classifierModelCorrected>
+		<classifierModelCleaned>./paperOutputModels/devCorrectedCleanedAll.model</classifierModelCleaned>
+		<classifierTable>sense_data_scaled</classifierTable>
+	</default>
+	
+	<IdentificationIncorporated>
+		<classifierModel>./outputModels/bestCompare.model</classifierModel>
+		<senseDb>wiktionary_data_sets</senseDb>
+		<senseTable>sense_data_scaled</senseTable>
+	</IdentificationIncorporated>
+	
+	<GoldenLabels>
+		<senseDb>wiktionary_data_sets</senseDb>
+		<senseTable>sense_data_scaled</senseTable>
+	</GoldenLabels>
+	
+</config>

File WiktionaryIdioms/config/nodbconfig.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<!-- config.xml -->
+<config>
+	<default>
+		<testPath>./data/dev_examples.txt</testPath>
+		<sensesPath>./data/dev_unannotated.txt</sensesPath>
+		<allSensesPath>./data/allsenses.txt</allSensesPath>
+		<classifierModelCorrected>./paperOutputModels/devCorrectedUncleanedAll.model</classifierModelCorrected>
+		<classifierModelCleaned>./paperOutputModels/devCorrectedCleanedAll.model</classifierModelCleaned>
+	</default>
+	
+	<IdentificationIncorporated>
+		<classifierModel>./outputModels/bestCompare.model</classifierModel>
+	</IdentificationIncorporated>
+	
+</config>

File WiktionaryIdioms/lib/ant-1.7.1.jar

Binary file added.

File WiktionaryIdioms/lib/ant-launcher-1.7.1.jar

Binary file added.

File WiktionaryIdioms/lib/commons-configuration-1.9.jar

Binary file added.

File WiktionaryIdioms/lib/commons-lang-2.6.jar

Binary file added.

File WiktionaryIdioms/lib/commons-lang3-3.1.jar

Binary file added.

File WiktionaryIdioms/lib/de.tudarmstadt.ukp.wikipedia.api-0.9.2.jar

Binary file added.

File WiktionaryIdioms/lib/de.tudarmstadt.ukp.wikipedia.datamachine-0.9.2-jar-with-dependencies.jar

Binary file added.

File WiktionaryIdioms/lib/de.tudarmstadt.ukp.wiktionary-0.16.1.jar

Binary file added.

File WiktionaryIdioms/lib/gson-2.2.2.jar

Binary file added.

File WiktionaryIdioms/lib/jaws-bin.jar

Binary file added.

File WiktionaryIdioms/lib/stanford-corenlp-1.3.5.jar

Binary file added.

File WiktionaryIdioms/lib/timestools.jar

Binary file added.

File WiktionaryIdioms/lib/wikokit-20120611.jar

Binary file added.

File WiktionaryIdioms/lib/xercesImpl-2.9.1-lucene.jar

Binary file added.

File WiktionaryIdioms/specifics/specifics.txt

+accounting
+advertising
+agriculture
+algebra
+analytical chemistry
+anatomy
+anthropology
+archaeology
+arithmetic
+astronomy
+automotive
+aviation
+architecture
+baseball
+basketball
+biblical
+bingo
+biology
+botany
+boxing
+broadcasting
+business
+cartography
+chemistry
+Christianity
+computer science
+computing
+construction
+cricket
+cryptography
+cycling
+dentistry
+design
+disease
+ecology
+economics
+electronics
+ethics
+enzyme
+epidemiology
+espionage
+fatty acid
+fantasy
+fashion
+fencing
+film
+finance
+firearms
+firefighting
+fish
+football
+game theory
+galaxy
+genetics
+geography
+geology
+geometry
+golf
+grammar
+graphtheory
+gymnastics
+gynaecology
+hematology
+ice hockey
+ichthyology
+information theory
+Internet
+Islam
+Judaism
+juggling
+legal
+linear algebra
+linguistics
+logic
+magic
+management
+marketing
+mathematics
+mechanics
+medicine
+medical
+meteorology
+military
+mineralogy
+muscle
+music
+mycology
+nautical
+networking
+neurology
+optics
+organic compound
+pathology
+pharmaceutical drug
+pharmacology
+philosophy
+phonetics
+phonology
+photography
+physics
+physiology
+poker
+politics
+printing
+programming
+protein
+psychology
+radio
+rhetoric
+rope
+rugby
+schools
+sports
+soccer
+sociology
+softball
+software
+star
+statistics
+stochastic processes
+sumo
+taxation
+taxonomy
+telecommunications
+television
+tennis
+thermodynamics
+topology
+trademark
+transport
+trigonometry
+typesetting
+typography
+user interface
+video games
+weapons
+wrestling
+zoology

File WiktionaryIdioms/src/classifier/classifiers/ClassificationResult.java

+package classifier.classifiers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.TreeMap;
+
+import classifier.model.ClassifierEvaluationUtils;
+import classifier.model.Sense;
+
+
+public class ClassificationResult {
+	public List<Integer> features;
+	public int iterations;
+	public double learningRate;
+	public List<double[]> prs;
+	public List<TreeMap<Integer, List<Sense>>> foldResults;
+	public TreeMap<Integer, List<Sense>> results;
+	
+	public ClassificationResult() {
+		
+	}
+	
+	public ClassificationResult(List<Integer> features, int iterations, double learningRate) {
+		this.features = features;
+		this.iterations = iterations;
+		this.learningRate = learningRate;
+		prs = new ArrayList<double[]>();
+	}
+	
+	public void setFoldResults(List<TreeMap<Integer, List<Sense>>> results) {
+		this.foldResults = results;
+	}
+	
+	public void setResults(TreeMap<Integer, List<Sense>> results) {
+		this.results = results;
+	}
+	
+	public void addPrecisionRecall(double[] pr) {
+		prs.add(pr);
+	}
+	
+	public void setPrecisionRecalls(List<double[]> prs) {
+		this.prs = prs; 
+	}
+	
+	public double getAverageFScore() {
+		return ClassifierEvaluationUtils.getAverageFMeasure(prs);
+	}
+	
+	public boolean isUnaryClassifier() {
+		return ClassifierEvaluationUtils.getAllOneClassifier(prs);
+	}
+	
+	public double getAveragePrecisionRecallDiff() {
+		double total = 0;
+		for (double[] pr : prs) {
+			total += Math.abs(pr[0] - pr[1]);
+		}
+		return total / prs.size();
+	}
+	
+	public String toString() {
+		String s = "Features: " + features + "\n";
+
+		s += "iterations: " + iterations + "\n";
+		s += "learningRate: " + learningRate + "\n";
+		for (double[] pr : prs) {
+			s += "p: " + pr[0] + "; ";
+			s += "r: " + pr[1] + "; ";
+			s += "f: " + ClassifierEvaluationUtils.getFMeasure(pr) + "\n";
+		}
+		s += Arrays.toString(ClassifierEvaluationUtils.getAveragedPrecisionRecall(prs)) + "\n";
+		s += getAverageFScore() + "\n";
+		return s;
+	}
+}

File WiktionaryIdioms/src/classifier/classifiers/Classifier.java

+package classifier.classifiers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.TreeMap;
+
+import classifier.model.ClassifierData;
+import classifier.model.ClassifierModel;
+import classifier.model.Result;
+import classifier.model.Sense;
+
+
+public abstract class Classifier {
+	
+	protected int numIterations;
+	protected double errorBound;
+	protected double learningRate;
+	protected double[] weights;
+	protected List<Integer> featureTypes;
+	
+	public Classifier(int numIterations, double errorBound, double learningRate, List<Integer> featureTypes) {
+		this.numIterations = numIterations;
+		this.errorBound = errorBound;
+		this.learningRate = learningRate;
+		this.featureTypes = featureTypes;
+	}
+	
+	public Classifier(ClassifierModel model) {
+		this.numIterations = model.numIterations;
+		this.errorBound = model.errorBound;
+		this.learningRate = model.learningRate;
+		this.featureTypes = model.features;
+		this.weights = model.weights;
+	}
+		
+	public abstract ClassifierModel train(List<ClassifierData> data);
+	
+	/**
+	 * Tests the List of Senses. For each data point, it predicts the class
+	 * based on the weights learned from the training step.
+	 * @param testPoints - the list of points to be classified
+	 * @return A map from label to list of DataPoint. These are organized such that all DataPoints
+	 *  with predicted class label are in label's list.
+	 */
+	public TreeMap<Integer, List<ClassifierData>> test(List<ClassifierData> testPoints) {
+		TreeMap<Integer, List<ClassifierData>> predictions = new TreeMap<Integer, List<ClassifierData>>();
+		// First go through and put a mapping for every class in
+		for (int label : Sense.getClasses()) {
+			predictions.put(label, new ArrayList<ClassifierData>());
+		}
+		for (int i = 0; i < testPoints.size(); i++) {
+			int pred = predict(testPoints.get(i));
+			if (!predictions.containsKey(pred)) {
+				predictions.put(pred, new ArrayList<ClassifierData>());
+			}
+			predictions.get(pred).add(testPoints.get(i));
+		}
+		return predictions;
+	}
+	
+	/**
+	 * Tests the List of Senses. For each data point, it predicts the class
+	 * based on the weights learned from the training step.
+	 * @param testPoints - the list of points to be classified
+	 * @return A map from label to list of DataPoint. These are organized such that all DataPoints
+	 *  with predicted class label are in label's list.
+	 */
+	public List<Result> testGetSortedDeltas(List<ClassifierData> testPoints) {
+		List<Result> predictions = new ArrayList<Result>();
+		// First go through and put a mapping for every class in
+
+		for (int i = 0; i < testPoints.size(); i++) {
+			Result pred = predictResult(testPoints.get(i));
+			predictions.add(pred);
+		}
+		Collections.sort(predictions);
+		return predictions;
+	}
+	
+	public double[] getWeights() {
+		return Arrays.copyOf(weights, weights.length);
+	}
+	
+	public int predict(ClassifierData point) {
+
+		double maxPred = 0;
+		int bestClass = Integer.MIN_VALUE;
+		for (int label : ClassifierData.getClasses()) {
+			double pred = 0;
+			double[] phiVals = ClassifierData.phi(point, label, featureTypes);
+			for (int i = 0; i < weights.length; i++) {
+				pred += (weights[i] * phiVals[i]);
+			}
+			if(pred > maxPred || bestClass == Integer.MIN_VALUE) {
+				maxPred = pred;
+				bestClass = label;
+			}
+		}
+		return bestClass;
+	}
+	
+	public Result predictResult(ClassifierData point) {
+
+		double litPred = 0;
+		double idiomPred = 0;
+		for (int label : ClassifierData.getClasses()) {
+			double pred = 0;
+			double[] phiVals = ClassifierData.phi(point, label, featureTypes);
+			for (int i = 0; i < weights.length; i++) {
+				pred += (weights[i] * phiVals[i]);
+			}
+			if (label == 0) {
+				litPred = pred;
+			} else if (label == 1) {
+				idiomPred = pred;
+			}
+		}
+		return new Result(point, litPred, idiomPred);
+	}
+	
+	public void setIterations(int iters) {
+		this.numIterations = iters;
+	}
+	
+	public void setErrorBound(double error) {
+		this.errorBound = error;
+	}
+	
+	public void setLearningRate(double learn) {
+		this.learningRate = learn;
+	}
+	
+	public int getIterations() {
+		return this.numIterations;
+	}
+	
+	public double getErrorBound() {
+		return errorBound;
+	}
+	
+	public double getLearningRate() {
+		return learningRate;
+	}
+	
+	public List<Integer> getFeatureTypes() {
+		List<Integer> copy = new ArrayList<Integer>(featureTypes);
+		return copy;
+	}
+
+}

File WiktionaryIdioms/src/classifier/classifiers/Perceptron.java

+package classifier.classifiers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import classifier.model.ClassifierData;
+import classifier.model.ClassifierModel;
+import classifier.model.Result;
+import classifier.model.Sense;
+
+
+public class Perceptron extends Classifier {
+	
+	public Perceptron(int numIterations, double errorBound, double learningRate, List<Integer> featureTypes) {
+		super(numIterations, errorBound, learningRate, featureTypes);
+	}
+	
+	public Perceptron(ClassifierModel model) {
+		super(model);
+	}
+	
+	public String toString() {
+		String s = "Perceptron: \n";
+		s += "iterations: " + numIterations + "\n";
+		s += "errorBound: " + errorBound + "\n";
+		s += "learningRate: " + learningRate + "\n";
+		s += "features: " + featureTypes + "\n";
+		return s;
+	}
+	
+	
+	public ClassifierModel train(List<ClassifierData> data) {
+		if (data.size() == 0) {
+			return null;
+		}
+		// Start with 0 weights
+		weights = new double[(featureTypes.size() + 1) * ClassifierData.getClasses().size()];
+		
+		int iters = 0;
+		double iterationError = errorBound;
+		while (iters < numIterations && iterationError >= errorBound) {
+			iters++;
+			
+			iterationError = 0;
+			
+			// accumulate update
+			double[] totalUpdate = new double[weights.length];
+			// Visit the training instances one by one.
+			for (int i = 0; i < data.size(); i++) {
+				// Make a prediction
+				int prediction = predict(data.get(i));
+		
+				// If wrong, adjust weights
+				if (prediction != data.get(i).getLabel()) {
+					update(totalUpdate, data.get(i), prediction);
+					// Accumulate iteration error.
+
+					iterationError += 1;
+				}
+			}
+			// Update the weights by adding the averaged update
+			averagedUpdateWeights(totalUpdate, data.size());
+			
+			iterationError = (iterationError / data.size());
+		}
+		
+		return new ClassifierModel(this);
+	}
+	
+	private void averagedUpdateWeights(double[] totalUpdate, int numExamples) {
+		for (int i = 0; i < weights.length; i++) {
+			weights[i] += (totalUpdate[i] / (numExamples * 1.0));
+		}
+	}
+
+	private void update(double[] totalUpdate, ClassifierData point, int pred) {
+		double[] correctPhis = ClassifierData.phi(point, point.getLabel(), featureTypes);
+		double[] wrongPhis = ClassifierData.phi(point, pred, featureTypes);
+		for (int i = 0; i < totalUpdate.length; i++) {
+			totalUpdate[i] = totalUpdate[i] + (learningRate * (correctPhis[i] - wrongPhis[i]));	
+		}
+	}
+	
+	public Result predictResultGeneral(Sense point) {
+
+		Result r = new Result(point);
+		for (int label : Sense.getClasses()) {
+			double pred = 0;
+			double[] phiVals = Sense.phi(point, label, featureTypes);
+			for (int i = 0; i < weights.length; i++) {
+				pred += (weights[i] * phiVals[i]);
+			}
+			r.addPrediction(label, pred);
+		}
+		return r;
+	}	
+}

File WiktionaryIdioms/src/classifier/classifiers/UntrustingPerceptron.java

+package classifier.classifiers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import classifier.model.ClassifierData;
+import classifier.model.ClassifierModel;
+import classifier.model.Result;
+import classifier.model.Sense;
+
+
+public class UntrustingPerceptron extends Classifier {
+	public static final double POS_CUTOFF = .8;
+
+	private int numIterations;
+	private double errorBound;
+	private double learningRate;
+	private double[] weights;
+	private List<Integer> featureTypes;
+	
+	public UntrustingPerceptron(int numIterations, double errorBound, double learningRate, List<Integer> featureTypes) {
+		super(numIterations, errorBound, learningRate, featureTypes);
+	}
+	
+	public UntrustingPerceptron(ClassifierModel model) {
+		super(model);
+	}
+	
+	public ClassifierModel train(List<ClassifierData> data) {
+		if (data.size() == 0) {
+			return null;
+		}
+		Set<ClassifierData> incognito = new HashSet<ClassifierData>();
+		Map<Integer, List<ClassifierData>> incogPreds = new HashMap<Integer, List<ClassifierData>>();
+		// Start with 0 weights
+		weights = new double[(featureTypes.size() + 1) * ClassifierData.getClasses().size()];
+		
+		int iters = 0;
+		double iterationError = errorBound;
+		while (iters < numIterations && iterationError >= errorBound) {
+			iters++;
+			
+			iterationError = 0;
+			
+			// accumulate update
+			double[] totalUpdate = new double[weights.length];
+			// Visit the training instances one by one.
+			for (int i = 0; i < data.size(); i++) {
+				// Make a prediction
+				int prediction = predict(data.get(i));
+		
+				int correctLabel = data.get(i).getLabel();
+				// If it is an incognito positive, make sure that it is still an error
+				if (incognito.contains(data.get(i))) {
+					// the label should actually be 1
+					correctLabel = 1;
+					
+					// count what it was predicted as
+					if (!incogPreds.containsKey(prediction)) {
+						incogPreds.put(prediction, new ArrayList<ClassifierData>());
+					}
+					incogPreds.get(prediction).add(data.get(i));
+				}
+				
+				// If wrong, adjust weights
+				if (prediction != correctLabel) {
+					
+					update(totalUpdate, data.get(i), prediction, correctLabel);
+					// Accumulate iteration error.
+
+					iterationError += 1;
+				}
+			}
+			// Update the weights by adding the averaged update
+			averagedUpdateWeights(totalUpdate, data.size());
+			
+			iterationError = (iterationError / data.size());
+			
+			// Update the incognito set
+			incognito = getUpdatedIncognito(incogPreds, data);
+			incogPreds = new HashMap<Integer, List<ClassifierData>>();
+			
+			//System.out.println("The incognito set size is: " + incognito.size());
+		}
+		return new ClassifierModel(this);
+	}
+	
+	private Set<ClassifierData> getUpdatedIncognito(
+			Map<Integer, List<ClassifierData>> incogPreds, List<ClassifierData> data) {
+		Set<ClassifierData> incognito = new HashSet<ClassifierData>();
+		
+		// If it classified the incognito sense correctly previously, keep it in the incognito set
+		if (incogPreds.containsKey(1)) {
+			incognito.addAll(incogPreds.get(1));
+		}
+		
+		// For the rest of the data, if it is a "negative" example, see if it actually looks positive.
+		List<Result> testResult = testGetSortedDeltas(data);
+		
+		double positiveCutoff = getPositiveCutoff(testResult);
+		for (Result r : testResult) {
+			if (r.getDifference() >= positiveCutoff) {
+				incognito.add(r.getClassifierData());
+			}
+		}
+		
+		return incognito;
+	}
+	
+	private double getPositiveCutoff(List<Result> results) {
+		// We want to get the number that POS_CUTOFF percent of positive examples are above
+		List<Result> positives = new ArrayList<Result>();
+		for (Result r : results) {
+			if (r.getClassifierData().getLabel() == 1) {
+				positives.add(r);
+			}
+		}
+		
+		int numBelowCutoff = (int) Math.floor(positives.size() * POS_CUTOFF);
+		
+		// Cutoff is the difference value at the numBelowCutoff - 1th element
+		return positives.get(numBelowCutoff - 1).getDifference();
+	}
+	
+	
+	private void averagedUpdateWeights(double[] totalUpdate, int numExamples) {
+		for (int i = 0; i < weights.length; i++) {
+			weights[i] += (totalUpdate[i] / (numExamples * 1.0));
+		}
+	}
+
+	private void update(double[] totalUpdate, ClassifierData point, int pred, int correct) {
+		double[] correctPhis = ClassifierData.phi(point, correct, featureTypes);
+		double[] wrongPhis = ClassifierData.phi(point, pred, featureTypes);
+		for (int i = 0; i < totalUpdate.length; i++) {
+			totalUpdate[i] = totalUpdate[i] + (learningRate * (correctPhis[i] - wrongPhis[i]));	
+		}
+	}
+}

File WiktionaryIdioms/src/classifier/distances/Distance.java

+package classifier.distances;
+
+import java.util.TreeMap;
+
+public interface Distance {
+	public static final TreeMap<String, Distance> TYPES = new TreeMap<String , Distance>() {/**
+		 * 
+		 */
+		private static final long serialVersionUID = 1L;
+
+	{
+	    put("wordnet_synonym_distance", new WordNetSynonym());
+	    put("wiktionary_synonym_distance", new WiktionarySynonym());
+
+	    put("wiktionary_onelevel_antonym_distance", new WiktionaryOneLevelAntonym());
+	    put("wordnet_onelevel_antonym_distance", new WordNetOneLevelAntonym());
+	    
+	    put("wordnet_hypernym_distance", new WordNetHypernym());
+	    put("wordnet_hyponym_distance", new WordNetHyponym());
+
+	    
+	}};
+	
+	
+	public int getDistance(String from, String target, int max);
+}

File WiktionaryIdioms/src/classifier/distances/WiktionaryOneLevelAntonym.java

+package classifier.distances;
+
+import java.util.Set;
+
+import classifier.utilities.WiktionaryUtils;
+
+
+import de.tudarmstadt.ukp.wiktionary.api.IWiktionaryEdition;
+import de.tudarmstadt.ukp.wiktionary.api.RelationType;
+
+public class WiktionaryOneLevelAntonym implements Distance {
+
+
+	@Override
+	public int getDistance(String from, String target, int max) {
+		IWiktionaryEdition wkt = WiktionaryUtils.getWiktionaryEdition();
+		// Get one level of antonyms from the from word
+		Set<String> antonyms = WiktionaryUtils.getRelationsForWord(from, wkt, RelationType.ANTONYM);
+				
+		// Then go and find the smallest distance according to synonyms.
+		// Max for the synonym distance should be one less that this because
+		// you've effectively already gone one level deep.
+		int leastDistance = -1;
+		for (String antFrom : antonyms) {
+			int dist = Distance.TYPES.get("wiktionary_synonym_distance").getDistance(antFrom, target, max);
+			if ((dist < leastDistance && dist >= 0) || (leastDistance == -1)) {
+				leastDistance = dist;
+			} 
+		}
+		return leastDistance;
+	}
+
+}

File WiktionaryIdioms/src/classifier/distances/WiktionarySynonym.java

+package classifier.distances;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import classifier.utilities.WiktionaryUtils;
+
+
+import de.tudarmstadt.ukp.wiktionary.api.IWiktionaryEdition;
+import de.tudarmstadt.ukp.wiktionary.api.RelationType;
+
+public class WiktionarySynonym implements Distance {
+
+	@Override
+	public int getDistance(String from, String target, int max) {
+		IWiktionaryEdition wkt = WiktionaryUtils.getWiktionaryEdition();
+		
+		Map<String, Integer> distances = new HashMap<String, Integer>();
+		Map<String, String> backs = new HashMap<String, String>();
+		
+		// Initialize by setting distance of from to 1
+		distances.put(from, 0);
+		
+		List<String> queue = new ArrayList<String>();
+		queue.add(from);
+		int currentDist = 0;
+		while (!queue.isEmpty() && currentDist < max) {
+			String current = queue.remove(0);
+			
+			if (!distances.containsKey(current) ||
+				current.equals(target)) {
+				break;
+			}
+			currentDist = distances.get(current);
+			// The synonyms are the neighbors of current
+			Set<String> syns = WiktionaryUtils.getRelationsForWord(current, wkt, RelationType.SYNONYM);
+			for (String syn : syns) {
+				int alt = distances.get(current) + 1;
+				// If it is not in distances yet or if the distance is
+				// shorter than what is already in distances, put it in
+				// and store the backpointer.
+				if (!distances.containsKey(syn) ||
+						distances.get(syn) > alt) {
+					distances.put(syn, alt);
+					backs.put(syn, current);
+					queue.add(syn);
+				}
+			}
+		}
+		if (distances.containsKey(target)) {
+			return distances.get(target);
+		}
+		return -1;
+	}
+
+}

File WiktionaryIdioms/src/classifier/distances/WordNetHypernym.java

+package classifier.distances;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import classifier.utilities.WordNetUtils;
+
+import edu.smu.tspell.wordnet.NounSynset;
+import edu.smu.tspell.wordnet.Synset;
+import edu.smu.tspell.wordnet.SynsetType;
+import edu.smu.tspell.wordnet.WordNetDatabase;
+
+public class WordNetHypernym implements Distance {
+
+	@Override
+	public int getDistance(String from, String target, int max) {
+		WordNetUtils.setDatabaseDirectory();
+		WordNetDatabase db = WordNetDatabase.getFileInstance();
+		Map<String, Integer> distances = new HashMap<String, Integer>();
+		Map<String, String> backs = new HashMap<String, String>();
+		
+		// Initialize by setting distance of from to 1
+		distances.put(from, 0);
+		
+		List<String> queue = new ArrayList<String>();
+		queue.add(from);
+		int currentDist = 0;
+		while (!queue.isEmpty() && currentDist < max) {
+			String current = queue.remove(0);
+			currentDist = distances.get(current);
+			
+			if (!distances.containsKey(current) ||
+				current.equals(target) ||
+				currentDist == max) {
+				break;
+			}
+			// The synonyms are the neighbors of current
+			Synset[] synsets = db.getSynsets(current, SynsetType.NOUN);
+			
+			// build the set of synonyms
+			Set<String> hypernyms = new HashSet<String>();
+			NounSynset ns;
+			for (Synset synset : synsets) {
+				ns = (NounSynset) synset;
+				NounSynset[] hypers = ns.getHypernyms();
+				for (NounSynset hypset : hypers) {
+					for (String hyp : hypset.getWordForms()) {
+						hypernyms.add(hyp);
+					}
+				}
+			}
+			
+			for (String syn : hypernyms) {
+				int alt = distances.get(current) + 1;
+				// If it is not in distances yet or if the distance is
+				// shorter than what is already in distances, put it in
+				// and store the backpointer.
+				if (!distances.containsKey(syn) ||
+						distances.get(syn) > alt) {
+					distances.put(syn, alt);
+					backs.put(syn, current);
+					queue.add(syn);
+				}
+			}
+		}
+		if (distances.containsKey(target)) {
+			return distances.get(target);
+		}
+		return -1;
+	}
+
+}

File WiktionaryIdioms/src/classifier/distances/WordNetHyponym.java

+package classifier.distances;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import classifier.utilities.WordNetUtils;
+
+import edu.smu.tspell.wordnet.NounSynset;
+import edu.smu.tspell.wordnet.Synset;
+import edu.smu.tspell.wordnet.SynsetType;
+import edu.smu.tspell.wordnet.WordNetDatabase;
+
+public class WordNetHyponym implements Distance {
+
+	@Override
+	public int getDistance(String from, String target, int max) {
+		WordNetUtils.setDatabaseDirectory();
+		WordNetDatabase db = WordNetDatabase.getFileInstance();
+		Map<String, Integer> distances = new HashMap<String, Integer>();
+		Map<String, String> backs = new HashMap<String, String>();
+		
+		// Initialize by setting distance of from to 1
+		distances.put(from, 0);
+		
+		List<String> queue = new ArrayList<String>();
+		queue.add(from);
+		int currentDist = 0;
+		while (!queue.isEmpty() && currentDist < max) {
+			String current = queue.remove(0);
+			currentDist = distances.get(current);
+			
+			if (!distances.containsKey(current) ||
+				current.equals(target) ||
+				currentDist == max) {
+				break;
+			}
+			// The synonyms are the neighbors of current
+			Synset[] synsets = db.getSynsets(current, SynsetType.NOUN);
+			
+			// build the set of synonyms
+			Set<String> hyponyms = new HashSet<String>();
+			NounSynset ns;
+			for (Synset synset : synsets) {
+				ns = (NounSynset) synset;
+				NounSynset[] hypos = ns.getHyponyms();
+				for (NounSynset hyposet : hypos) {
+					for (String hypo : hyposet.getWordForms()) {
+						hyponyms.add(hypo);
+					}
+				}
+			}
+			
+			for (String syn : hyponyms) {
+				int alt = distances.get(current) + 1;
+				// If it is not in distances yet or if the distance is
+				// shorter than what is already in distances, put it in
+				// and store the backpointer.
+				if (!distances.containsKey(syn) ||
+						distances.get(syn) > alt) {
+					distances.put(syn, alt);
+					backs.put(syn, current);
+					queue.add(syn);
+				}
+			}
+		}
+		if (distances.containsKey(target)) {
+			return distances.get(target);
+		}
+		return -1;
+	}
+}

File WiktionaryIdioms/src/classifier/distances/WordNetOneLevelAntonym.java

+package classifier.distances;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import classifier.utilities.WordNetUtils;
+
+import edu.smu.tspell.wordnet.Synset;
+import edu.smu.tspell.wordnet.WordNetDatabase;
+import edu.smu.tspell.wordnet.WordSense;
+
+public class WordNetOneLevelAntonym implements Distance {
+
+	@Override
+	public int getDistance(String from, String target, int max) {
+		
+		WordNetUtils.setDatabaseDirectory();
+		WordNetDatabase db = WordNetDatabase.getFileInstance();
+		
+		// Get one level of antonyms from the from word
+		// The synonyms are the neighbors of current
+		
+		// The synonyms are the neighbors of current
+		Synset[] synsets = db.getSynsets(from);
+					
+		// build the set of synonyms
+		Set<String> antonyms = new HashSet<String>();
+		for (int i = 0; i < synsets.length; i++) { 
+		    Synset s = (synsets[i]);
+		    for (String word : s.getWordForms()) {
+		    	WordSense[] ws = s.getAntonyms(word);
+		    	for (WordSense w : ws) {
+		    		antonyms.add(w.getWordForm());
+		    	}
+		    }
+		}
+				
+		// Then go and find the smallest distance according to synonyms.
+		// Max for the synonym distance should be one less that this because
+		// you've effectively already gone one level deep.
+		int leastDistance = -1;
+		for (String antFrom : antonyms) {
+			int dist = Distance.TYPES.get("wordnet_synonym_distance").getDistance(antFrom, target, max);
+			if ((dist < leastDistance && dist >= 0) || (leastDistance == -1)) {
+				leastDistance = dist;
+			}
+		}
+		return leastDistance;
+	}
+}

File WiktionaryIdioms/src/classifier/distances/WordNetSynonym.java

+package classifier.distances;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import classifier.utilities.WordNetUtils;
+
+
+import edu.smu.tspell.wordnet.Synset;
+import edu.smu.tspell.wordnet.WordNetDatabase;
+
+public class WordNetSynonym implements Distance {
+	
+	public int getDistance(String from, String target, int max) {
+		WordNetUtils.setDatabaseDirectory();
+		WordNetDatabase db = WordNetDatabase.getFileInstance();
+		Map<String, Integer> distances = new HashMap<String, Integer>();
+		Map<String, String> backs = new HashMap<String, String>();
+		
+		// Initialize by setting distance of from to 1
+		distances.put(from, 0);
+		
+		List<String> queue = new ArrayList<String>();
+		queue.add(from);
+		int currentDist = 0;
+		while (!queue.isEmpty() && currentDist < max) {
+			String current = queue.remove(0);
+			currentDist = distances.get(current);
+			
+			if (!distances.containsKey(current) ||
+				current.equals(target) ||
+				currentDist == max) {
+				break;
+			}
+			// The synonyms are the neighbors of current
+			Synset[] synsets = db.getSynsets(current);
+			
+			// build the set of synonyms
+			Set<String> synonyms = new HashSet<String>();
+			for (Synset synset : synsets) {
+				for (String syn : synset.getWordForms()) {
+					synonyms.add(syn);
+				}
+			}
+			
+			for (String syn : synonyms) {
+				int alt = distances.get(current) + 1;
+				// If it is not in distances yet or if the distance is
+				// shorter than what is already in distances, put it in
+				// and store the backpointer.
+				if (!distances.containsKey(syn) ||
+						distances.get(syn) > alt) {
+					distances.put(syn, alt);
+					backs.put(syn, current);
+					queue.add(syn);
+				}
+			}
+		}
+		if (distances.containsKey(target)) {
+			return distances.get(target);
+		}
+		return -1;
+	}
+}

File WiktionaryIdioms/src/classifier/experiments/BasicApply.java

+package classifier.experiments;
+
+import java.io.File;
+import java.util.List;
+import java.util.TreeMap;
+
+import classifier.classifiers.Classifier;
+import classifier.model.ClassifierData;
+import classifier.model.ClassifierModel;
+import classifier.model.Result;
+import classifier.model.Sense;
+import config.ClassifierConfigs;
+
+public class BasicApply implements Experiment {
+	public static final String CONFIG_STR = "BasicApply";
+
+	@Override
+	public ExperimentResult runExperiment(ClassifierConfigs configs, List<ClassifierData> train, List<ClassifierData> test) {
+		// TODO Auto-generated method stub
+		configs.setSection(CONFIG_STR);
+		
+		boolean verbose = configs.getSBool(ClassifierConfigs.VERBOSE);
+		
+		System.out.println("verbose: " + verbose);
+		
+		String modelFile = configs.getSString("modelFile");
+		Classifier classy = null;
+		ClassifierModel resultModel = null;
+		if (modelFile.length() > 0) {
+			System.out.println("Loading from model file: " + modelFile);
+			resultModel = new ClassifierModel(new File(modelFile));
+			classy = configs.getClassifier(resultModel);
+		} else {
+			classy = configs.getSClassifier();
+			resultModel = classy.train(train);
+		}
+		
+		System.out.println(classy);
+
+		TreeMap<Integer, List<ClassifierData>> results = classy.test(test);
+		List<Result> deltas = classy.testGetSortedDeltas(test);
+		
+		ExperimentResult exResult = new ExperimentResult(resultModel);
+
+		exResult.addResultSets(results, deltas);
+		
+		exResult.setClassifierInfo(classy.toString());
+		
+		exResult.weights = classy.getWeights();
+		
+		return exResult;
+	}
+
+}

File WiktionaryIdioms/src/classifier/experiments/Bootstrapping.java

+package classifier.experiments;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+
+import classifier.classifiers.Classifier;
+import classifier.model.ClassifierData;
+import classifier.model.ClassifierEvaluationUtils;
+import classifier.model.ClassifierModel;
+import classifier.model.Result;
+import classifier.model.Sense;
+import classifier.utilities.ClassifierDataUtils;
+import config.ClassifierConfigs;
+
+public class Bootstrapping implements Experiment {
+	public static final String CONFIG_STR = "Bootstrapping";
+
+	@Override
+	public ExperimentResult runExperiment(ClassifierConfigs configs, List<ClassifierData> train, List<ClassifierData> test) {
+		// TODO Auto-generated method stub
+		configs.setSection(CONFIG_STR);
+		
+		boolean verbose = configs.getSBool(ClassifierConfigs.VERBOSE);
+		int iterations = configs.getSInt("iterations");
+		double cutoffMin = configs.getSDouble("cutoffMin");
+		double cutoffMax = configs.getSDouble("cutoffMax");
+		double cutoffIncrement = configs.getSDouble("cutoffIncrement");
+		
+		System.out.println("verbose: " + verbose);
+		String modelFile = configs.getSString("modelFile");
+		
+		
+		// get original labels
+		Map<String, Integer> originals = new HashMap<String, Integer>();
+		for (ClassifierData cd : train) {
+			originals.put(cd.getKey(), cd.getLabel());
+		}
+		for (ClassifierData cd : test) {
+			originals.put(cd.getKey(), cd.getLabel());
+		}
+		
+		List<ExperimentResult> results = new ArrayList<ExperimentResult>();
+		for (double i = cutoffMin; i <= cutoffMax; i += cutoffIncrement) {
+			System.out.println("*************************");
+			System.out.println("cutoff: " + i);
+			Classifier classy = null;
+			ClassifierModel resultModel = null;
+			if (modelFile.length() > 0) {
+				System.out.println("Loading from model file: " + modelFile);
+				resultModel = new ClassifierModel(new File(modelFile));
+				classy = configs.getClassifier(resultModel);
+			}			
+			
+			System.out.println("Base classifier:");
+			System.out.println(classy);
+			System.out.println(ClassifierDataUtils.getGeneralDataAnalysis(train));
+			System.out.println(ClassifierDataUtils.getGeneralDataAnalysis(test));
+
+			
+			List<ExperimentResult> subResults = runBootstrap(configs, classy, train, test, iterations, i);
+			results.addAll(subResults);
+			
+			// reset original labels
+			for (ClassifierData cd : train) {
+				cd.setLabel(originals.get(cd.getKey()));
+			}
+			for (ClassifierData cd : test) {
+				cd.setLabel(originals.get(cd.getKey()));
+			}			
+		}
+		
+		return results.get(0);
+	}
+	
+	private static List<ExperimentResult> runBootstrap(ClassifierConfigs configs, Classifier classy, 
+			List<ClassifierData> train, List<ClassifierData> test, 
+			int iterations, double cutoff) {
+		List<ExperimentResult> exResults = new ArrayList<ExperimentResult>();
+		
+		int count = 1;
+		TreeMap<Integer, List<ClassifierData>> results = classy.test(test);
+		double prevFMeasure = ClassifierEvaluationUtils.getFMeasure(results, 1);
+		System.out.println("F-measure: " + prevFMeasure);
+		double change = prevFMeasure;
+		
+		while (count <= iterations) {
+			// use the classifier to re-label the training
+			List<Result> trainingDeltas = classy.testGetSortedDeltas(train);
+			
+			TreeMap<Integer, List<ClassifierData>> classifications = 
+					ExperimentResult.produceClassificationsFromCutoff(trainingDeltas, cutoff);
+			
+			for (int label : classifications.keySet()) {
+				for (ClassifierData cd : classifications.get(label)) {
+					cd.setLabel(label);
+				}
+			}
+			
+			System.out.println("###########");
+			System.out.println("iteration: " + count);
+			count++;
+
+			System.out.println(ClassifierDataUtils.getGeneralDataAnalysis(train));
+			System.out.println(ClassifierDataUtils.getGeneralDataAnalysis(test));
+
+			
+			// now train a new classifier with this training data
+			Experiment subE = new CompareGroups();
+			ExperimentResult subResult = subE.runExperiment(configs, train, test);
+			exResults.add(subResult);
+
+			classy = configs.getClassifier(subResult.model);
+			results = classy.test(test);
+			double fMeasure = ClassifierEvaluationUtils.getFMeasure(results, 1);
+			
+			change = fMeasure - prevFMeasure;
+			prevFMeasure = fMeasure;
+			
+			System.out.println(subResult);
+			System.out.println("F-measure: " + fMeasure);
+			System.out.println("change: " + change);
+			System.out.println();
+		}
+		return exResults;
+	}
+
+	
+}

File WiktionaryIdioms/src/classifier/experiments/CompareFeatures.java

+package classifier.experiments;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import classifier.classifiers.Classifier;
+import classifier.model.ClassifierData;
+
+import config.ClassifierConfigs;
+
+public class CompareFeatures implements Experiment {
+	public static final String CONFIG_STR = "CompareFeatures";
+
+	@Override
+	public ExperimentResult runExperiment(ClassifierConfigs configs, List<ClassifierData> train,
+			List<ClassifierData> test) {
+		configs.setSection(CONFIG_STR);
+				
+		boolean verbose = configs.getSBool(ClassifierConfigs.VERBOSE);
+				
+		System.out.println("verbose: " + verbose);
+		
+		double errorBound = configs.getSDouble(ClassifierConfigs.ERROR_BOUND);
+		double learningDelta = configs.getSDouble("learningDelta");
+		int iterationMax = configs.getSInt("iterationMax");
+		
+		System.out.println("learning delta: " + learningDelta);
+		System.out.println("iteration max: " + iterationMax);
+				
+		List<List<Integer>> listOfFeatures = new ArrayList<List<Integer>>();
+		String[] arr = configs.getSStringArray(ClassifierConfigs.FEATURES);
+		// add each feature in its own list to the list of features
+		for (String s : arr) {
+			List<Integer> feat = new ArrayList<Integer>();
+			feat.add(Integer.parseInt(s));
+			listOfFeatures.add(feat);
+			break;
+		}
+
+		if (configs.getSBool("buildUp")) {
+			for (int i = 1; i < arr.length; i++) {
+				List<Integer> feat = new ArrayList<Integer>();
+				for (int j = 0; j <= i; j++) {
+					feat.add(Integer.parseInt(arr[j]));
+				}
+				listOfFeatures.add(feat);
+			}
+		}
+		
+		boolean buildBest = configs.getSBool("buildByBest");
+		
+		System.out.println("Feature combos to be tested: " + listOfFeatures);
+		System.out.println("Later, we will determine the build up by best: " + buildBest);
+		System.out.println();
+
+		ExperimentResult maxBest = null;
+		String completeInfo = "features\trecall\tprecision\tfscore\titerations\tweights\n";
+		String graphInfo = "features & recall & precision & fscore & iterations\n";
+		
+		Map<Integer, Double> bestSingles = new HashMap<Integer, Double>();
+		while (true) {
+			for (List<Integer> feats : listOfFeatures) {
+				// set the features for the grid search
+			
+				Classifier classy = configs.getClassifier(0, errorBound, 0, feats);
+				// Do a grid search for each feature setting
+				List<ExperimentResult> result = 
+						GridSearch.gridSearch(classy, learningDelta, iterationMax, train, test);
+			
+				ExperimentResult best = GridSearch.getBestResult(result);
+			
+				if (feats.size() == 1) {
+					bestSingles.put(feats.get(0), best.getFScore());
+				}
+			
+				if (maxBest == null || maxBest.getFScore() < best.getFScore()) {
+					maxBest = best;
+				}
+			
+				completeInfo += best.model.features + "\t";
+				completeInfo += best.getRecall() + "\t";
+				completeInfo += best.getPrecision() + "\t";
+				completeInfo += best.getFScore() + "\t";
+				completeInfo += best.model.numIterations + "\t";
+				completeInfo += Arrays.toString(best.weights) + "\n";
+				
+				graphInfo += best.model.features + " & ";
+				graphInfo += best.getRecall() + " & ";
+				graphInfo += best.getPrecision() + " & ";
+				graphInfo += best.getFScore() + " & ";
+				graphInfo += best.model.numIterations + "\n";
+				if (verbose) {
+					System.out.println(best);
+				}
+			}
+		
+		
+			if (buildBest) {
+				// We're done with the singles, so add the builded ones to the end
+				int[] ordered = getOrderedList(bestSingles);
+				listOfFeatures.clear();
+				for (int i = 1; i < ordered.length; i++) {
+					List<Integer> feat = new ArrayList<Integer>();
+					for (int j = 0; j <= i; j++) {
+						feat.add(ordered[j]);
+					}
+					Collections.sort(feat);
+					listOfFeatures.add(feat);
+				}
+				buildBest = false;
+			} else {
+				break;
+			}
+		}
+		
+		maxBest.addPrintInfo(completeInfo);
+		maxBest.addGraphFormatInfo(graphInfo);
+
+		return maxBest;
+	}
+	
+	public int[] getOrderedList(Map<Integer, Double> vals) {
+		int[] l = new int[vals.size()];
+		int count = 0;
+		for (int i : vals.keySet()) {
+			l[count] = i;
+			count++;
+		}
+		selectionSort(l, vals); 
+		return l;
+	}
+	
+	public static void selectionSort(int[] x, Map<Integer, Double> vals) {
+	    for (int i=0; i<x.length-1; i++) {
+	        for (int j=i+1; j<x.length; j++) {
+	            if (vals.get(x[i]) < vals.get(x[j])) {
+	                //... Exchange elements
+	                int temp = x[i];
+	                x[i] = x[j];
+	                x[j] = temp;
+	            }
+	        }
+	    }
+	}
+}

File WiktionaryIdioms/src/classifier/experiments/CompareGroups.java

+package classifier.experiments;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import classifier.classifiers.Classifier;
+import classifier.features.numeric.Feature;
+import classifier.model.ClassifierData;
+
+import config.ClassifierConfigs;
+
+public class CompareGroups implements Experiment {
+	public static final String CONFIG_STR = "CompareGroups";
+
+	@Override
+	public ExperimentResult runExperiment(ClassifierConfigs configs, List<ClassifierData> train,
+			List<ClassifierData> test) {
+		configs.setSection(CONFIG_STR);
+				
+		boolean verbose = configs.getSBool(ClassifierConfigs.VERBOSE);
+				
+		System.out.println("verbose: " + verbose);
+		
+		double errorBound = configs.getSDouble(ClassifierConfigs.ERROR_BOUND);
+		double learningDelta = configs.getSDouble("learningDelta");
+		int iterationMax = configs.getSInt("iterationMax");
+		
+		System.out.println("learning delta: " + learningDelta);
+		System.out.println("iteration max: " + iterationMax);
+				
+		List<List<Integer>> listOfFeatures = new ArrayList<List<Integer>>();
+		
+		System.out.println("Feature groups to be tested: ");
+		listOfFeatures.add(getList(Feature.LEXICAL));
+		listOfFeatures.add(getList(Feature.GRAPH));
+
+		List<Integer> part12 = getList(Feature.LEXICAL);
+		part12.addAll(getList(Feature.GRAPH));
+		listOfFeatures.add(part12);
+
+		
+		System.out.println(listOfFeatures);
+
+		ExperimentResult maxBest = null;
+		String completeInfo = "features\trecall\tprecision\tfscore\titerations\tweights\n";
+		String graphInfo = "features & recall & precision & fscore & iterations\n";
+				
+		for (List<Integer> feats : listOfFeatures) {
+			// set the features for the grid search
+			
+			Classifier classy = configs.getClassifier(0, errorBound, 0, feats);
+			// Do a grid search for each feature setting
+			List<ExperimentResult> result = 
+					GridSearch.gridSearch(classy, learningDelta, iterationMax, train, test);
+			
+			ExperimentResult best = GridSearch.getBestResult(result);
+			
+			if (maxBest == null || maxBest.getFScore() < best.getFScore()) {
+				maxBest = best;
+			}
+			
+			completeInfo += best.model.features + "\t";
+			completeInfo += best.getRecall() + "\t";
+			completeInfo += best.getPrecision() + "\t";
+			completeInfo += best.getFScore() + "\t";
+			completeInfo += best.model.numIterations + "\t";
+			completeInfo += Arrays.toString(best.weights) + "\n";
+				
+			graphInfo += best.model.features + " & ";