package edu.stanford.nlp.sempre.freebase;
import fig.basic.*;
import java.util.List;
import edu.stanford.nlp.sempre.*;
/**
* Used to evaluate Freebase question answering.
* Denotation is a list of entities.
* Nothing in here is specific to Freebase, but this is not really meant to be
* a general-purpose class.
*
* @author Percy Liang
*/
public class FreebaseValueEvaluator implements ValueEvaluator {
public static class Options {
@Option(gloss = "When evaluating lists, compute F1 rather than exact match") public boolean useF1 = true;
}
public static final Options opts = new Options();
public double getCompatibility(Value target, Value pred) {
double f1 = getF1(target, pred);
return opts.useF1 ? f1 : (f1 == 1 ? 1 : 0);
}
// Compute F1 score between two lists (partial match).
// this is target, that is predicted.
private double getF1(Value target, Value pred) {
List<Value> targetList = ((ListValue) target).values;
if (!(pred instanceof ListValue)) return 0;
List<Value> predList = ((ListValue) pred).values;
if (targetList.size() == 0 && predList.size() == 0)
return 1;
if (targetList.size() == 0 || predList.size() == 0)
return 0;
double precision = 0;
for (Value v2 : predList) { // For every predicted value...
double score = 0;
for (Value v1 : targetList)
score = Math.max(score, getItemCompatibility(v1, v2));
precision += score;
}
precision /= predList.size();
assert precision >= 0 && precision <= 1 : precision;
double recall = 0;
for (Value v1 : targetList) { // For every true value...
double score = 0;
for (Value v2 : predList)
score = Math.max(score, getItemCompatibility(v1, v2));
recall += score;
}
recall /= targetList.size();
assert recall >= 0 && recall <= 1 : recall;
if (precision + recall == 0) return 0;
double f1 = 2 * precision * recall / (precision + recall);
assert f1 >= 0 && f1 <= 1 : f1;
return f1;
}
// Compare one element of the list.
public double getItemCompatibility(Value target, Value pred) {
if (target instanceof DescriptionValue) {
// Just has to match the description
if (pred instanceof NameValue)
return ((DescriptionValue) target).value.equals(((NameValue) pred).description) ? 1 : 0;
return 0;
}
if (pred instanceof ErrorValue) return 0; // Never award points for error
if (pred == null) {
LogInfo.warning("Predicted value is null!");
return 0;
}
if (target.getClass() != pred.getClass()) return 0;
if (target instanceof DateValue) {
DateValue targetDate = (DateValue) target;
DateValue predDate = (DateValue) pred;
// Only comparing the year right now! This is crude.
boolean match = (targetDate.year == predDate.year);
return match ? 1 : 0;
}
return target.equals(pred) ? 1 : 0;
}
}