/////////////////////////////////////////////////////////////////////// // VerbLearn System // // A crosslinguistic bodily-grounded hand-action // verb semantics acquisition system. // // David Bailey 4/97 // // File: Generator.java // // Description: Generates ungrounded scenario descriptions subject // to given restrictions and also some sanity conditions. // // Classes: Generator import java.io.*; import java.util.*; /////////////////////////////////////////////////////////////////////// // Generates ungrounded scenario descriptions subject to given // restrictions and also some sanity conditions. // // The code is general except for the fixOrReject() routine which does // a lot of futzing around with the specific linking features in the // current design. class Generator { private Fstruct w, l; // World-state and full linking f-struct private int rejects; // FORMAT: "java Generator startnum num-scenarios [constraints]" // eg: "java Generator 1 100 'schema=slide'" // public static void main(String[] args) throws IOException, FileNotFoundException { new VerbLearn().outsideInit(true); int start = Integer.parseInt(args[0]); int n = Integer.parseInt(args[1]); Fstruct r; if (args.length > 2) { r = new Fstruct(args[2]); } else { r = new Fstruct(""); } Generator g = new Generator(start, n, r); } Generator(int start, int n, Fstruct r) { System.out.println("// Generated scenarios:\n"); for (int i = start; i < start + n; i++) { generateScenario(r); System.out.println("sc" + i + "\t" + w.toString4() + "\t" + l.toString4()); } System.out.println("// " + n + " outputs, " + rejects + " rejects."); } // Obey the restrictions in 'r'. // Leaves result strings in 'w' and 'l' (world-state and full linking // f-structs respectively). private void generateScenario(Fstruct r) { StringBuffer wBuf, lBuf; while (true) { wBuf = new StringBuffer(); Enumeration fEnum = VerbLearn.context().params().worldFeatureNames(); while (fEnum.hasMoreElements()) { String f = (String)fEnum.nextElement(); if (r.isSet(f)) { wBuf.append(f + "=" + r.get(f) + " "); } else { Vector vv = VerbLearn.context().params().featureVals(f); int vIdx = (int)(Math.random() * vv.size()); wBuf.append(f + "=" + (String)vv.elementAt(vIdx) + " "); } } lBuf = new StringBuffer(wBuf.toString()); fEnum = VerbLearn.context().params().motorFeatureNames(); while (fEnum.hasMoreElements()) { String f = (String)fEnum.nextElement(); if (r.isSet(f)) { lBuf.append(f + "=" + r.get(f) + " "); } else { Vector vv = VerbLearn.context().params().featureVals(f); int vIdx = (int)(Math.random() * vv.size()); lBuf.append(f + "=" + (String)vv.elementAt(vIdx) + " "); } } w = new Fstruct(wBuf.toString()); l = new Fstruct(lBuf.toString()); if (fixOrReject(w, l)) break; rejects++; } } // The sanity conditions. May modify w and l, or return false to // reject the Fstructs entirely. private boolean fixOrReject(Fstruct w, Fstruct l) { // CHANGE FEATURES: // Mess with relative frequency of schemas: double prob = Math.random(); if (prob < 0.4) {l.set("schema", "slide");} else if (prob < 0.55) {l.set("schema", "lift");} else if (prob < 0.65) {l.set("schema", "rotate");} else if (prob < 0.71) {l.set("schema", "depress");} else {l.set("schema", "touch");} // change probability of depressible or contact to be lower than .5: boolean newDepressible = l.get("schema").equals("depress"); boolean newContact = (Math.random() < 0.15); w.set("depressible", new Boolean(newDepressible).toString()); l.set("depressible", new Boolean(newDepressible).toString()); w.set("contact", new Boolean(newContact).toString()); l.set("contact", new Boolean(newContact).toString()); // Button has fixed properties: if (l.get("depressible").equals("true")) { w.set("elongated", "false"); l.set("elongated", "false"); } // Adjust postures in each schema: if (l.get("schema").equals("slide")) { if (l.get("size").equals("small")) { l.set("posture", "grasp"); } else { l.set("posture", "palm"); } } if (l.get("schema").equals("lift")) { if (l.get("size").equals("small")) { if (l.get("elongated").equals("false")) { l.set("posture", "pinch"); } else { l.set("posture", "wrap"); } } else { l.set("posture", "platform"); } } if (l.get("schema").equals("rotate")) { if (l.get("size").equals("small")) { l.set("posture", "pinch"); } else { l.set("posture", "grasp"); } } if (l.get("schema").equals("depress")) { l.set("posture", "index"); if (l.get("contact").equals("true")) { l.set("accel", "zero"); } } if (l.get("schema").equals("touch")) { if (Math.random() < 0.5) { l.set("posture", "index"); } else { l.set("posture", "palm"); } } // Make sure dir and elbow are compatible: if (l.get("schema").equals("slide") || l.get("schema").equals("touch")) { if (l.get("dir").equals("away")) { l.set("elbow", "extend"); } else if (l.get("dir").equals("toward")) { l.set("elbow", "flex"); } } // Make sure dir in lift is up: if (l.get("schema").equals("lift")) { l.set("dir", "up"); } // Make sure dur in touch is sensible: if (l.get("schema").equals("touch") && l.get("accel").equals("high")) { l.set("dur", "short"); } // Make sure for touch there's no elbow motion if already contacting: if (l.get("contact").equals("true") && l.get("schema").equals("touch")) { l.set("elbow", "fixed"); } // UNSET FEATURES (mainly...): if (l.get("schema").equals("rotate")) { l.unset("elbow"); } if (l.get("schema").equals("lift") && l.get("accel").equals("zero")) { l.unset("elbow"); } if (l.get("schema").equals("depress")) { l.unset("elbow"); // l.unset("accel"); l.unset("dir"); } if (l.get("schema").equals("touch") && l.get("contact").equals("true")) { l.set("elbow", "fixed"); l.unset("dir"); } // REJECT THE WHOLE THING: // Check directions for each schema: if (l.get("schema").equals("slide") && (l.get("dir").equals("up") || l.get("dir").equals("down"))) { return false; } if (l.get("schema").equals("rotate") && (l.get("dir").equals("up") || l.get("dir").equals("down"))) { return false; } if (l.get("schema").equals("touch") && l.isSet("dir") && (l.get("dir").equals("up") || l.get("dir").equals("toward"))) { return false; } // Make sure force, accel, and size are compatible if (l.isSet("size") && l.isSet("force") && l.isSet("accel")) { int forceExcess = val(l.get("force")) - val(l.get("accel")); if (l.get("schema").equals("slide") || l.get("schema").equals("rotate")) { if ((l.get("size").equals("small") && (forceExcess<-1 || forceExcess>0)) || (l.get("size").equals("large") && (forceExcess<0 || forceExcess>1))) { return false; } } else if (l.get("schema").equals("lift")) { if ((l.get("size").equals("small") && (forceExcess<0 || forceExcess>1)) || (l.get("size").equals("large") && (forceExcess<1 || forceExcess>2))) { return false; } } } if (l.isSet("force") && l.isSet("accel") && l.get("schema").equals("touch")) { if (!l.get("force").equals(l.get("accel"))) { return false; } } // Make sure the accel is non-zero except for lift: if ((l.get("schema").equals("slide") || l.get("schema").equals("rotate") || l.get("schema").equals("touch")) && l.get("accel").equals("zero")) { return false; } // Repeated actions must be short-duration: if (l.isSet("aspect") && l.isSet("dur") && l.get("aspect").equals("iterated") && !l.get("dur").equals("short")) { return false; } // FINALLY, RETURN TRUE (AND MODIFIED W AND L) return true; } private int val(String s) { if (s.equals("zero")) return 0; if (s.equals("low")) return 1; if (s.equals("med")) return 2; if (s.equals("high")) return 3; return -999; } }