package edu.stanford.nlp.sempre.overnight; import com.google.common.collect.Lists; import fig.basic.*; import edu.stanford.nlp.sempre.*; import java.util.*; /** * Functions for supporting a simple database. * This is very inefficient and it works only for small worlds. * Example applications: calendar, blocks world * * Types: DateValue, TimeValue, Value * All arguments are lists of Values. * * @author Jonathan Berant * @author Yushi Wang */ public final class SimpleWorld { public static class Options { @Option(gloss = "Number of entity samples") public int numOfValueSamples = 60; @Option(gloss = "Domain specifies which predicates/entities exist in the world") public String domain; @Option(gloss = "Verbosity") public int verbose = 0; @Option(gloss = "Path to load up the DB from (triples)") public String dbPath = null; @Option(gloss = "When performing a join with getProperty, do we want to deduplicate?") public boolean joinDedup = true; } public static Options opts = new Options(); private SimpleWorld() { } // en.person.alice => en.person private static String extractType(String id) { int i = id.lastIndexOf('.'); if (id.charAt(i + 1) == '_') { //to deal with /fb:en.lake._st_clair and such id = id.substring(0, i); i = id.lastIndexOf('.'); return id.substring(0, i); } else return id.substring(0, i); } private static String getType(Value v) { if (v instanceof NumberValue) { String unit = ((NumberValue) v).unit; return unit + "_number"; // So we can quickly tell if something is a number or not } else if (v instanceof DateValue) { return "en.date"; } else if (v instanceof TimeValue) { return "en.time"; } else if (v instanceof BooleanValue) { return "en.boolean"; } else if (v instanceof NameValue) { return extractType(((NameValue) v).id); } else if (v instanceof ListValue) { return getType(((ListValue) v).values.get(0)); } else { throw new RuntimeException("Can't get type of value " + v); } } // Make sure that the types of the objects in the two lists are the same private static void checkTypeMatch(List<Value> l1, List<Value> l2) { for (Value o1 : l1) { for (Value o2 : l2) { if (!getType(o1).equals(getType(o2))) throw new RuntimeException("Intersecting objects with non-matching types, object 1: " + o1 + ", object2: " + o2); } } } private static <T> boolean intersects(List<T> l1, List<T> l2) { //optimization if (l1.size() < l2.size()) { for (T o1 : l1) { if (l2.contains(o1)) return true; } } else { for (T o2 : l2) { if (l1.contains(o2)) return true; } } return false; } // Modes of superlatives private static final String MIN = "min"; private static final String MAX = "max"; //////////////////////////////////////////////////////////// // Methods exposed to the public. public static List<Value> singleton(Value value) { return Collections.singletonList(value); } // Return the set of entities who can be the first argument of property public static List<Value> domain(String property) { createWorld(); String type1 = propertyToType1.get(property); if (type1 == null) throw new RuntimeException("Property " + property + " has no type1"); return getProperty(singleton(new NameValue(type1)), reverse("type")); } public static String reverse(String property) { if (property.startsWith("!")) return property.substring(1); return "!" + property; } // Return the concatenation of two lists. public static List<Value> concat(Value v1, Value v2) { return concat(singleton(v1), singleton(v2)); } public static List<Value> concat(List<Value> l1, List<Value> l2) { checkTypeMatch(l1, l2); if (l1.equals(l2)) // Disallow 'alice' or 'alice' throw new RuntimeException("Cannot concatenate two copies of the same list: " + l1); List<Value> newList = new ArrayList<Value>(); newList.addAll(l1); newList.addAll(l2); return newList; } private static void checkType1(String property, Value e1) { String type1 = propertyToType1.get(property); String type2 = "?"; if (type1 == null) throw new RuntimeException("Property " + property + " has no type1"); if (!getType(e1).equals(type1)) throw new RuntimeException("Type check failed: " + property + " : (-> " + type1 + " " + type2 + ") doesn't match arg1 " + e1 + " : " + getType(e1)); } private static void checkType2(String property, Value e2) { String type1 = "?"; String type2 = propertyToType2.get(property); if (type2 == null) throw new RuntimeException("Property " + property + " has no type2"); if (!getType(e2).equals(type2)) throw new RuntimeException("Type check failed: " + property + " : (-> " + type1 + " " + type2 + ") doesn't match arg2 " + e2 + " : " + getType(e2)); } private static void ensureNonnumericType2(String property) { createWorld(); String type2 = propertyToType2.get(property); if (type2 == null) throw new RuntimeException("Property " + property + " has no type2"); if (type2.endsWith("_number") || type2.equals("en.date") || type2.equals("en.time")) throw new RuntimeException("Property " + property + " has numeric type2, which is not allowed"); } public static String ensureNumericProperty(String property) { createWorld(); String type2 = propertyToType2.get(property); if (type2.endsWith("number") || type2.equals("en.date") || type2.equals("en.time")) { return property; } throw new RuntimeException("Property " + property + " has non-numeric type2, which is not allowed"); } public static List<Value> ensureNumericEntity(Value value) { return ensureNumericEntity(singleton(value)); } public static List<Value> ensureNumericEntity(List<Value> list) { createWorld(); String type = getType(list.get(0)); if (type.endsWith("number") || type.equals("en.date") || type.equals("en.time")) { return list; } throw new RuntimeException("List " + list + " is non-numeric, which is not allowed"); } // Return the subset of |objects| whose |property| |compare| refValues. public static List<Value> filter(List<Value> entities, String property) { // Unary properties return filter(entities, property, "=", singleton(new BooleanValue(true))); } public static List<Value> filter(List<Value> entities, String property, String compare, Value refValue) { return filter(entities, property, compare, singleton(refValue)); } public static List<Value> filter(List<Value> entities, String property, String compare, List<Value> refValues) { List<Value> newEntities = new ArrayList<>(); for (Value v : refValues) checkType2(property, v); for (Value obj : entities) { if (!(obj instanceof NameValue)) continue; NameValue e = (NameValue) obj; List<Value> values = lookupDB(e, property); boolean match = false; checkType1(property, e); if (compare.equals("=")) { match = intersects(values, refValues); } else if (compare.equals("!=")) { match = !intersects(values, refValues); // Note this is not the existential interpretation! } else if (compare.equals("<")) { match = getDegree(values, MIN) < getDegree(refValues, MAX); } else if (compare.equals(">")) { match = getDegree(values, MAX) > getDegree(refValues, MIN); } else if (compare.equals("<=")) { match = getDegree(values, MIN) <= getDegree(refValues, MAX); } else if (compare.equals(">=")) { match = getDegree(values, MAX) >= getDegree(refValues, MIN); } if (match) newEntities.add(e); } return newEntities; } private static double getDouble(Value v) { if (!(v instanceof NumberValue)) throw new RuntimeException("Not a number: " + v); return ((NumberValue) v).value; } // Degree is used to compare (either take the max or min). private static double getDegree(List<Value> values, String mode) { double deg = Double.NaN; for (Value v : values) { double x = getDegree(v); if (Double.isNaN(deg) || (mode.equals(MAX) ? x > deg : x < deg)) deg = x; } return deg; } private static double getDegree(Value value) { if (value instanceof TimeValue) { TimeValue timeValue = (TimeValue) value; return timeValue.hour; } else if (value instanceof DateValue) { DateValue dateValue = (DateValue) value; double dValue = 0; if (dateValue.year != -1) dValue += dateValue.year * 10000; if (dateValue.month != -1) dValue += dateValue.month * 100; if (dateValue.day != -1) dValue += dateValue.day; return dValue; } else if (value instanceof NumberValue) { return ((NumberValue) value).value; } else { throw new RuntimeException("Can't get degree from " + value); } } // Return the subset of entities that obtain the min/max value of property. public static List<Value> superlative(List<Value> entities, String mode, String property) { List<Value> bestEntities = null; double bestDegree = Double.NaN; for (Value e : entities) { double degree = getDegree(lookupDB(e, property), mode); checkType1(property, e); if (bestEntities == null || (mode.equals(MAX) ? degree > bestDegree : degree < bestDegree)) { bestEntities = new ArrayList<Value>(); bestEntities.add(e); bestDegree = degree; } else if (degree == bestDegree) { bestEntities.add(e); } } return bestEntities; } // Return the subset of entities that obtain the most/least number of values of property that fall in restrictors. public static List<Value> countSuperlative(List<Value> entities, String mode, String property) { return countSuperlative(entities, mode, property, null); } //make sure lists are returned in a unique order public static String sortAndToString(Object obj) { if (obj instanceof List) { List<String> strList = new ArrayList<>(); List list = (List) obj; for (Object listObj: list) strList.add(listObj.toString()); Collections.sort(strList); return strList.toString(); } return obj.toString(); } public static List<Value> countSuperlative(List<Value> entities, String mode, String property, List<Value> restrictors) { List<Value> bestEntities = null; double bestDegree = Double.NaN; if (restrictors != null) { for (Value v : restrictors) checkType2(property, v); } ensureNonnumericType2(property); for (Value e : entities) { List<Value> values = lookupDB(e, property); double degree = 0; for (Value v : values) if (restrictors == null || restrictors.contains(v)) degree++; checkType1(property, e); if (bestEntities == null || (mode.equals(MAX) ? degree > bestDegree : degree < bestDegree)) { bestEntities = new ArrayList<Value>(); bestEntities.add(e); bestDegree = degree; } else if (degree == bestDegree) { bestEntities.add(e); } } return bestEntities; } // Return subset of entities that have the number of values of property that meet the mode/threshold criteria (e.g. >= 3). public static List<Value> countComparative(List<Value> entities, String property, String mode, NumberValue thresholdValue) { return countComparative(entities, property, mode, thresholdValue, null); } public static List<Value> countComparative(List<Value> entities, String property, String mode, NumberValue thresholdValue, List<Value> restrictors) { List<Value> newEntities = new ArrayList<>(); double threshold = getDouble(thresholdValue); if (restrictors != null) { for (Value v : restrictors) checkType2(property, v); } ensureNonnumericType2(property); for (Value e : entities) { List<Value> values = lookupDB(e, property); double degree = 0; for (Value v : values) if (restrictors == null || restrictors.contains(v)) degree++; checkType1(property, e); switch (mode) { case "=": if (degree == threshold) newEntities.add(e); break; case "<": if (degree < threshold) newEntities.add(e); break; case ">": if (degree > threshold) newEntities.add(e); break; case "<=": if (degree <= threshold) newEntities.add(e); break; case ">=": if (degree >= threshold) newEntities.add(e); break; default: throw new RuntimeException("Illegal mode: " + mode); } } return newEntities; } // Return sum of values. public static List<Value> sum(List<Value> values) { double sum = 0; for (Value v : values) sum += getDouble(v); return Collections.singletonList(new NumberValue(sum)); } // Return sum/mean/min/max of values. public static List<Value> aggregate(String mode, List<Value> values) { // Note: this is probably too strong to reject empty lists. if (values.size() == 0) throw new RuntimeException("Can't aggregate " + mode + " over empty list"); double sum = 0; for (Value v : values) { // Note: we're leaving out dates and times, but sum/avg doesn't quite work with them anyway. if (!(v instanceof NumberValue)) throw new RuntimeException("Can only aggregate over numbers, but got " + v); double x = getDouble(v); sum += x; } double result; switch (mode) { case "avg": result = sum / values.size(); break; case "sum": result = sum; break; default: throw new RuntimeException("Bad mode: " + mode); } return Collections.singletonList(new NumberValue(result, ((NumberValue) values.get(0)).unit)); } // Return the properties of the entities (database join). public static List<Value> getProperty(Value inObject, String property) { return getProperty(singleton(inObject), property); } public static List<Value> getProperty(List<Value> inObjects, String property) { List<Value> outObjects = new ArrayList<>(); Set<Value> outObjectsCache = new HashSet<>(); //optimization - run "contains" on set and not list for (Value obj : inObjects) { List<Value> values = lookupDB(obj, property); checkType1(property, obj); for (Value v : values) { if (!opts.joinDedup || !outObjectsCache.contains(v)) { outObjects.add(v); outObjectsCache.add(v); } } } if (outObjects.size() == 0) throw new RuntimeException("The property " + property + " does not appear in any of the objects " + inObjects); return outObjects; } private static double arithOp(String op, double v1, double v2) { switch (op) { case "+": return v1 + v2; case "-": return v1 - v2; case "*": return v1 * v2; case "/": return v1 / v2; default: throw new RuntimeException("Invalid operation: " + op); } } public static List<Value> arithOp(String op, Value v1, Value v2) { return singleton(new NumberValue(arithOp(op, getDouble(v1), getDouble(v2)))); } public static List<Value> arithOp(String op, List<Value> args1, List<Value> args2) { // FUTURE: should pay attention to units List<Value> result = new ArrayList<Value>(); for (Value v1 : args1) for (Value v2 : args2) result.addAll(arithOp(op, v1, v2)); return result; } //////////////////////////////////////////////////////////// // Internal state of the world private static final Random random = new Random(1); private static Set<Value> entities; // Keep track of all the entities private static Set<String> properties; // Keep track of all the properties private static Map<String, String> propertyToType1, propertyToType2; // types private static Map<Pair<Value, String>, List<Value>> database; // Database consists of (e1, property, e2) triples public static int sizeofDB() { return database.size(); } public static List<Value> lookupDB(Value e, String property) { createWorld(); if (!entities.contains(e)) throw new RuntimeException("DB doesn't contain entity " + e); if (!properties.contains(property)) throw new RuntimeException("DB doesn't contain property " + property); List<Value> values = database.get(new Pair(e, property)); if (values == null) return Collections.EMPTY_LIST; return values; } private static void insertDB(Value e1, String property) { // For unary properties insertDB(e1, property, new BooleanValue(true)); } private static void insertDB(Value e1, String property, List<Value> e2s) { for (Value e2 : e2s) insertDB(e1, property, e2); } private static void insertDB(Value e1, String property, Value e2) { //LogInfo.logs("insertDB (%s, %s, %s)", e1, property, e2); entities.add(e1); properties.add(property); properties.add(reverse(property)); entities.add(e2); MapUtils.addToList(database, new Pair(e1, property), e2); MapUtils.addToList(database, new Pair(e2, reverse(property)), e1); propertyToType1.put(property, getType(e1)); propertyToType2.put(property, getType(e2)); propertyToType1.put(reverse(property), getType(e2)); propertyToType2.put(reverse(property), getType(e1)); } public static void dumpDatabase() { for (Pair<Value, String> pair : database.keySet()) LogInfo.logs("%s %s %s", pair.getFirst(), pair.getSecond(), database.get(pair)); } // Used for testing public static void recreateWorld() { database = null; createWorld(); } public static void createWorld() { if (database != null) return; entities = new HashSet<>(); properties = new HashSet<>(); database = new HashMap<>(); propertyToType1 = new HashMap<>(); propertyToType2 = new HashMap<>(); Domain domain = null; switch (opts.domain) { case "blocks": domain = new BlocksDomain(); break; case "calendar": domain = new CalendarDomain(); break; case "housing": domain = new HousingDomain(); break; case "restaurants": domain = new RestaurantsDomain(); break; case "publications": domain = new PublicationDomain(); break; case "socialnetwork": domain = new SocialNetworkDomain(); break; case "basketball": domain = new BasketballDomain(); break; case "recipes": domain = new RecipesDomain(); break; case "geo880": opts.dbPath = "lib/data/overnight/geo880.db"; domain = new ExternalDomain(); break; case "external": domain = new ExternalDomain(); break; default: throw new RuntimeException("Unknown domain: " + opts.domain); } domain.createEntities(opts.numOfValueSamples); // Dump the entire database LogInfo.begin_track("SimpleWorld.createWorld: domain = %s (%d entity/property pairs)", opts.domain, database.size()); if (opts.verbose >= 1) { dumpDatabase(); } LogInfo.end_track(); } private static <T> List<T> L(T... list) { return Arrays.asList(list); } // Convert the Object back to a Value private static Value toValue(Object obj) { if (obj instanceof Value) return (Value) obj; if (obj instanceof Boolean) return new BooleanValue((Boolean) obj); if (obj instanceof Integer) return new NumberValue((Integer) obj, "count"); if (obj instanceof Double) return new NumberValue((Double) obj); if (obj instanceof String) return new StringValue((String) obj); if (obj instanceof List) { List<Value> list = Lists.newArrayList(); for (Object elem : (List) obj) list.add(toValue(elem)); return new ListValue(list); } throw new RuntimeException("Unhandled object: " + obj + " with class " + obj.getClass()); } // Convert the Object to list value public static ListValue listValue(Object obj) { Value value = toValue(obj); if (value instanceof ListValue) { ListValue lv = (ListValue) value; Collections.sort(lv.values, new Value.ValueComparator()); return (ListValue) value; } return new ListValue(singleton(value)); } public static int sampleInt(int min, int max) { return random.nextInt(max - min) + min; } public static boolean sampleBernoulli(double prob) { return random.nextDouble() < prob; } // Choose a single random element from the list public static <T> T sampleMultinomial(List<T> list) { return list.get(sampleInt(0, list.size())); } // Choose n random elements from list (duplicates are possible). public static <T> List<T> sampleMultinomial(List<T> list, int n) { List<T> sublist = new ArrayList<T>(); if (list.size() > 0) { for (int i = 0; i < n; i++) sublist.add(sampleMultinomial(list)); } return sublist; } // Keep each element with probability |prob|. public static <T> List<T> subsample(List<T> list, double prob) { List<T> sublist = new ArrayList<T>(); for (T x : list) if (sampleBernoulli(prob)) sublist.add(x); return sublist; } // With high probability, return one of the first few to avoid empty denotations. public static <T> T focusSampleMultinomial(List<T> list) { if (sampleBernoulli(0.5)) return list.get(0); return list.get(sampleInt(0, list.size())); } public abstract static class Domain { public abstract void createEntities(int numEntities); } // Create |numEntities| entities, the first few have ids. private static List<Value> makeValues(List<String> ids) { return makeValues(ids.size(), ids); } private static List<Value> makeValues(int numEntities, List<String> ids) { List<Value> values = new ArrayList<Value>(); String type = extractType(ids.get(0)); for (int i = 0; i < numEntities; i++) values.add(makeValue(i < ids.size() ? ids.get(i) : type + "." + i, type)); return values; } private static Value makeValue(String id) { return makeValue(id, extractType(id)); } private static Value makeValue(String id, String type) { Value e = new NameValue(id); if (!entities.contains(e)) { insertDB(e, "type", new NameValue(type)); } return e; } // All dates for all domains are assumed to be in this range. private static DateValue sampleDate() { return new DateValue(sampleInt(2000, 2010), -1, -1); } //////////////////////////////////////////////////////////// // Specific domains (important to synchronize the constants with overnight/<domain>grammar!) public static class BlocksDomain extends Domain { public void createEntities(int numEntities) { List<Value> blocks = makeValues(numEntities, L("en.block.block1", "en.block.block2")); List<Value> shapes = makeValues(L("en.shape.pyramid", "en.shape.cube")); List<Value> colors = makeValues(L("en.color.red", "en.color.green")); for (Value e : blocks) { insertDB(e, "shape", sampleMultinomial(shapes)); insertDB(e, "color", sampleMultinomial(colors)); insertDB(e, "length", new NumberValue(sampleInt(2, 8), "en.inch")); insertDB(e, "width", new NumberValue(sampleInt(2, 8), "en.inch")); insertDB(e, "height", new NumberValue(sampleInt(2, 8), "en.inch")); insertDB(e, "left", sampleMultinomial(blocks)); insertDB(e, "right", sampleMultinomial(blocks)); insertDB(e, "above", sampleMultinomial(blocks)); insertDB(e, "below", sampleMultinomial(blocks)); if (sampleBernoulli(0.5)) insertDB(e, "is_special"); } } } public static class CalendarDomain extends Domain { private static DateValue sampleDate() { return new DateValue(2015, 1, sampleInt(1, 5)); } private static TimeValue sampleTime() { return new TimeValue(sampleInt(9, 16), 0); } public void createEntities(int numEntities) { List<Value> meetings = makeValues(numEntities, L("en.meeting.weekly_standup", "en.meeting.annual_review")); List<Value> people = makeValues(L("en.person.alice", "en.person.bob")); List<Value> locations = makeValues(L("en.location.greenberg_cafe", "en.location.central_office")); for (Value e : meetings) { insertDB(e, "date", sampleDate()); insertDB(e, "start_time", sampleTime()); insertDB(e, "end_time", sampleTime()); insertDB(e, "length", new NumberValue(sampleInt(1, 4), "en.hour")); insertDB(e, "attendee", sampleMultinomial(people, 2)); insertDB(e, "location", sampleMultinomial(locations)); if (sampleBernoulli(0.5)) insertDB(e, "is_important"); } } } public static class RestaurantsDomain extends Domain { public static final List<String> RESTAURANT_VPS = Arrays.asList("reserve,credit,outdoor,takeout,delivery,waiter,kids,groups".split(",")); public static final List<String> RESTAURANT_CUISINES = Arrays.asList("en.cuisine.thai,en.cuisine.french,en.cuisine.italian".split(",")); public static final List<String> RESTAURANT_MEALS = Arrays.asList("en.food.breakfast,en.food.lunch,en.food.dinner".split(",")); public static final List<String> NEIGHBORHOODS = Arrays.asList("en.neighborhood.tribeca,en.neighborhood.midtown_west,en.neighborhood.chelsea".split(",")); public void createEntities(int numEntities) { List<Value> restaurants = makeValues(numEntities, L("en.restaurant.thai_cafe", "en.restaurant.pizzeria_juno")); List<Value> neighborhoods = makeValues(NEIGHBORHOODS); List<Value> cuisines = makeValues(RESTAURANT_CUISINES); List<Value> meals = makeValues(RESTAURANT_MEALS); for (Value e : restaurants) { insertDB(e, "star_rating", new NumberValue(sampleInt(0, 6), "en.star")); insertDB(e, "price_rating", new NumberValue(sampleInt(1, 5), "en.dollar_sign")); insertDB(e, "num_reviews", new NumberValue(sampleInt(20, 60), "en.review")); insertDB(e, "neighborhood", sampleMultinomial(neighborhoods)); insertDB(e, "cuisine", sampleMultinomial(cuisines)); insertDB(e, "meals", subsample(meals, 0.5)); for (String vp : RESTAURANT_VPS) { if (sampleBernoulli(0.5)) insertDB(e, vp); } } } } public static class HousingDomain extends Domain { public static final List<String> HOUSING_VPS = Arrays.asList("allows_cats,allows_dogs,has_private_bath,has_private_room".split(",")); public static final List<String> HOUSING_TYPES = Arrays.asList("en.housing.apartment,en.housing.condo,en.housing.house,en.housing.flat".split(",")); public static final List<String> NEIGHBORHOODS = Arrays.asList("en.neighborhood.tribeca,en.neighborhood.midtown_west,en.neighborhood.chelsea".split(",")); public void createEntities(int numEntities) { List<Value> units = makeValues(numEntities, L("en.housing_unit.123_sesame_street", "en.housing_unit.900_mission_ave")); List<Value> housingTypes = makeValues(HOUSING_TYPES); List<Value> neighborhoods = makeValues(NEIGHBORHOODS); for (Value e : units) { insertDB(e, "rent", new NumberValue((double) sampleMultinomial(L(1500, sampleInt(1000, 3000))), "en.dollar")); insertDB(e, "size", new NumberValue((double) sampleMultinomial(L(800, sampleInt(500, 1500))), "en.square_feet")); insertDB(e, "posting_date", sampleDate()); insertDB(e, "neighborhood", sampleMultinomial(neighborhoods)); insertDB(e, "housing_type", sampleMultinomial(housingTypes)); for (String vp : HOUSING_VPS) { if (sampleBernoulli(0.5)) insertDB(e, vp); } } } } public static class PublicationDomain extends Domain { public void createEntities(int numEntities) { List<Value> articles = makeValues(numEntities, L("en.article.multivariate_data_analysis")); List<Value> people = makeValues(L("en.person.efron", "en.person.lakoff")); List<Value> venues = makeValues(L("en.venue.computational_linguistics", "en.venue.annals_of_statistics")); for (Value e : articles) { insertDB(e, "author", sampleMultinomial(people, 2)); insertDB(e, "venue", sampleMultinomial(venues)); insertDB(e, "publication_date", sampleDate()); insertDB(e, "cites", sampleMultinomial(articles, sampleInt(1, 10))); insertDB(e, "won_award"); } } } public static class SocialNetworkDomain extends Domain { public void createEntities(int numEntities) { List<Value> people = makeValues(numEntities, L("en.person.alice", "en.person.bob")); List<Value> genders = makeValues(L("en.gender.male", "en.gender.female")); List<Value> relationshipStatuses = makeValues(L("en.relationship_status.single", "en.relationship_status.married")); List<Value> cities = makeValues(L("en.city.new_york", "en.city.beijing")); List<Value> universities = makeValues(L("en.university.brown", "en.university.berkeley", "en.university.ucla")); List<Value> fields = makeValues(L("en.field.computer_science", "en.field.economics", "en.field.history")); List<Value> companies = makeValues(L("en.company.google", "en.company.mckinsey", "en.company.toyota")); List<Value> jobTitles = makeValues(L("en.job_title.ceo", "en.job_title.software_engineer", "en.job_title.program_manager")); for (Value e : people) { insertDB(e, "gender", sampleMultinomial(genders)); insertDB(e, "relationship_status", sampleMultinomial(relationshipStatuses)); insertDB(e, "height", new NumberValue(sampleInt(150, 210), "en.cm")); insertDB(e, "birthdate", sampleDate()); insertDB(e, "birthplace", sampleMultinomial(cities)); insertDB(e, "friend", sampleMultinomial(people, sampleInt(0, 3))); if (sampleBernoulli(0.5)) insertDB(e, "logged_in"); } for (Value e : makeValues(numEntities, L("en.education.0"))) { insertDB(e, "student", focusSampleMultinomial(people)); insertDB(e, "university", sampleMultinomial(universities)); insertDB(e, "field_of_study", sampleMultinomial(fields)); insertDB(e, "education_start_date", sampleDate()); insertDB(e, "education_end_date", sampleDate()); } for (Value e : makeValues(numEntities, L("en.employment.0"))) { insertDB(e, "employee", focusSampleMultinomial(people)); insertDB(e, "employer", sampleMultinomial(companies)); insertDB(e, "job_title", sampleMultinomial(jobTitles)); insertDB(e, "employment_start_date", sampleDate()); insertDB(e, "employment_end_date", sampleDate()); } } } public static class BasketballDomain extends Domain { public void createEntities(int numEntities) { List<Value> players = makeValues(numEntities, L("en.player.kobe_bryant", "en.player.lebron_james")); List<Value> teams = makeValues(L("en.team.lakers", "en.team.cavaliers")); List<Value> positions = makeValues(L("en.position.point_guard", "en.position.forward")); for (Value e : makeValues(numEntities, L("en.stats.0"))) { insertDB(e, "player", focusSampleMultinomial(players)); insertDB(e, "position", sampleMultinomial(positions)); insertDB(e, "team", sampleMultinomial(teams)); insertDB(e, "season", sampleDate()); insertDB(e, "num_points", new NumberValue(sampleInt(0, 10), "point")); insertDB(e, "num_assists", new NumberValue(sampleInt(0, 10), "assist")); insertDB(e, "num_steals", new NumberValue(sampleInt(0, 10), "steal")); insertDB(e, "num_turnovers", new NumberValue(sampleInt(0, 10), "turnover")); insertDB(e, "num_rebounds", new NumberValue(sampleInt(0, 10), "rebound")); insertDB(e, "num_blocks", new NumberValue(sampleInt(0, 10), "block")); insertDB(e, "num_fouls", new NumberValue(sampleInt(0, 10), "foul")); insertDB(e, "num_games_played", new NumberValue(sampleInt(0, 10), "game")); } } } public static class RecipesDomain extends Domain { public void createEntities(int numEntities) { List<Value> recipes = makeValues(numEntities, L("en.recipe.rice_pudding", "en.recipe.quiche")); List<Value> cuisines = makeValues(L("en.cuisine.chinese", "en.cuisine.french")); List<Value> ingredients = makeValues(L("en.ingredient.milk", "en.ingredient.spinach")); List<Value> meals = makeValues(L("en.meal.lunch", "en.meal.dinner")); for (Value e : recipes) { insertDB(e, "preparation_time", new NumberValue(sampleInt(5, 30), "en.minute")); insertDB(e, "cooking_time", new NumberValue(sampleInt(5, 30), "en.minute")); insertDB(e, "cuisine", sampleMultinomial(cuisines)); insertDB(e, "requires", sampleMultinomial(ingredients)); insertDB(e, "meal", sampleMultinomial(meals)); insertDB(e, "posting_date", sampleDate()); } } } // Domain that corresponds to reading from a file public static class ExternalDomain extends Domain { public void createEntities(int numEntities) { LogInfo.begin_track("ExternalDomain.createEntities: %s", opts.dbPath); // Load up from database for (String line : IOUtils.readLinesHard(opts.dbPath)) { String[] tokens = line.split("\t"); String pred = tokens[0]; Value e = makeValue(tokens[1]); if (tokens.length == 2) { // Unary insertDB(e, pred); } else if (tokens.length == 3) { // Binary Value f; if (tokens[2].startsWith("fb:en.")) // Named entity f = makeValue(tokens[2]); else f = Value.fromString(tokens[2]); // Number insertDB(e, pred, f); } else { throw new RuntimeException("Unhandled: " + line); } } LogInfo.end_track(); } } }