package edu.stanford.nlp.sempre.overnight;
import com.google.common.base.Joiner;
import edu.stanford.nlp.io.IOUtils;
import edu.stanford.nlp.stats.ClassicCounter;
import edu.stanford.nlp.stats.Counter;
import edu.stanford.nlp.stats.Counters;
import fig.basic.LispTree;
import fig.basic.MapUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Word-aligns original utterances with their paraphrases
* Created by joberant on 2/20/15.
*/
public class Aligner {
private Map<String, Counter<String>> model = new HashMap<>();
public double getCondProb(String target, String source) {
if (model.containsKey(source)) {
if (model.get(source).containsKey(target))
return model.get(source).getCount(target);
}
return 0d;
}
public int size() { return model.size(); }
//takes an example file and creates a model
public void heuristicAlign(String exampleFile, int threshold) {
model.clear();
Iterator<LispTree> iter = LispTree.proto.parseFromFile(exampleFile);
while (iter.hasNext()) {
LispTree tree = iter.next();
LispTree utteranceTree = tree.child(1);
LispTree originalTree = tree.child(2);
String utterance = preprocessUtterance(utteranceTree.child(1).value);
String original = preprocessUtterance(originalTree.child(1).value);
String[] utteranceTokens = utterance.split("\\s+");
String[] originalTokens = original.split("\\s+");
align(utteranceTokens, originalTokens);
}
normalize(threshold);
}
public void saveModel(String out) throws IOException {
PrintWriter writer = IOUtils.getPrintWriter(out);
for (String source: model.keySet()) {
Counter<String> counts = model.get(source);
for (String target: counts.keySet()) {
writer.println(Joiner.on('\t').join(source, target, counts.getCount(target)));
}
}
}
//normalize all the counts to get conditional probabilities
private void normalize(int threshold) {
for (String source: model.keySet()) {
Counter<String> counts = model.get(source);
Counters.removeKeys(counts, Counters.keysBelow(counts, threshold));
Counters.normalize(counts);
}
}
//count every co-occurrence
private void align(String[] utteranceTokens, String[] originalTokens) {
for (String utteranceToken: utteranceTokens) {
for (String originalToken: originalTokens) {
MapUtils.putIfAbsent(model, utteranceToken.toLowerCase(), new ClassicCounter<>());
MapUtils.putIfAbsent(model, originalToken.toLowerCase(), new ClassicCounter<>());
model.get(utteranceToken.toLowerCase()).incrementCount(originalToken.toLowerCase());
model.get(originalToken.toLowerCase()).incrementCount(utteranceToken.toLowerCase());
}
}
}
//remove '?' and '.'
public String preprocessUtterance(String utterance) {
if (utterance.endsWith("?"))
return utterance.substring(0, utterance.length() - 1);
if (utterance.endsWith("."))
return utterance.substring(0, utterance.length() - 1);
return utterance;
}
//read from serialized file
public static Aligner read(String path) {
Aligner res = new Aligner();
for (String line: edu.stanford.nlp.io.IOUtils.readLines(path)) {
String[] tokens = line.split("\t");
MapUtils.putIfAbsent(res.model, tokens[0], new ClassicCounter<>());
res.model.get(tokens[0]).incrementCount(tokens[1], Double.parseDouble(tokens[2]));
}
return res;
}
private void berkeleyAlign(String file, int threshold) {
for (String line: IOUtils.readLines(file)) {
String[] tokens = line.split("\t");
String[] sourceTokens = tokens[0].split("\\s+");
String[] targetTokens = tokens[1].split("\\s+");
String[] alignmentTokens = tokens[2].split("\\s+");
for (String alignmentToken: alignmentTokens) {
String[] alignment = alignmentToken.split("-");
Integer source = Integer.parseInt(alignment[0]);
Integer target = Integer.parseInt(alignment[1]);
MapUtils.putIfAbsent(model, sourceTokens[source], new ClassicCounter<>());
MapUtils.putIfAbsent(model, targetTokens[target], new ClassicCounter<>());
model.get(sourceTokens[source]).incrementCount(targetTokens[target]);
model.get(targetTokens[target]).incrementCount(sourceTokens[source]);
}
}
normalize(threshold);
}
//args[0] - example file with utterance and original
//args[1] - output file
//args[2] - heuristic or berkeley
//args[3] - threshold
public static void main(String[] args) {
Aligner aligner = new Aligner();
int threshold = Integer.parseInt(args[3]);
if (args[2].equals("heuristic"))
aligner.heuristicAlign(args[0], threshold);
else if (args[2].equals("berkeley"))
aligner.berkeleyAlign(args[0], threshold);
else throw new RuntimeException("bad alignment mode: " + args[2]);
try {
aligner.saveModel(args[1]);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}