PageRenderTime 67ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/code/LiteralAbstract1.java

http://silkin.googlecode.com/
Java | 1182 lines | 935 code | 69 blank | 178 comment | 450 complexity | 4188606e05d1c8b519cf58cb7bb7e623 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. import java.util.* ;
  2. import java.text.* ;
  3. import java.io.* ;
  4. /** This abstract class begins to define a Literal in Prolog syntax, consisting of a {@link Predicate} and an
  5. ArrayList<Object> of zero or more {@link Argument}s. Literals are the basic building blocks of
  6. Horn Clauses. They also are the level at which 90% of the action takes place in Example-Generation.
  7. <p>
  8. Because so many methods are defined at the Literal level, the code files are broken into 3 classes: this one,
  9. LiteralAbstract2, and Literal.
  10. @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
  11. */
  12. public abstract class LiteralAbstract1 extends Argument {
  13. private static int serializer = 31;
  14. // NOTE: the class-level (static) method finalConstraintCheck is defined near constraintCheck below.
  15. public static String failReason;
  16. public static boolean negativeConstraintPhase = false;
  17. public static int expansionSerial, debugSerial = 0;
  18. public static final String stdEgo = "Ego", stdAlter = "Alter";
  19. public static final String[] argCodes = {"A".intern(), "B".intern(), "C".intern(), "D".intern(), "E".intern(),
  20. "F".intern(), "G".intern(), "H".intern(), "I".intern(), "J".intern(),
  21. "K".intern(), "L".intern(), "M".intern(),
  22. "N".intern(), "O".intern(), "P".intern(), "Q".intern(), "R".intern(),
  23. "S".intern(), "T".intern(), "U".intern(), "V".intern(), "W".intern(),
  24. "X".intern(), "Y".intern(), "Z".intern(),
  25. "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH", "II", "JJ", "KK",
  26. "LL", "MM", "NN", "OO", "PP", "QQ", "RR", "SS", "TT", "UU", "VV",
  27. "WW", "XX", "YY", "ZZ"}; // 54 variables SHOULD be enough!
  28. public static final String[] cancellingPredsA = { "male", "female", "elder", "younger" },
  29. cancellingPredsB = { "female", "male", "younger", "elder" },
  30. oppositePredsA = { "father", "husband", "son", "brother", "mother", "wife", "daughter", "sister" },
  31. oppositePredsB = { "mother", "wife", "daughter", "sister", "father", "husband", "son", "brother" },
  32. generalPreds = { "parents", "spice", "children", "siblings", "parents", "spice", "children", "siblings" };
  33. public static ArrayList<Object> cancelPredsA = loadCanA(),
  34. cancelPredsB = loadCanB(),
  35. oppoPredsA = loadOppoA(),
  36. oppoPredsB = loadOppoB(),
  37. genPreds = loadGenPreds();
  38. // INSTANCE VARIABLES
  39. public Predicate predicate;
  40. public ArrayList<Object> args = new ArrayList<Object>();
  41. static ArrayList<Object> loadCanA() {
  42. ArrayList<Object> canA = new ArrayList<Object>();
  43. for (int i=0; i < cancellingPredsA.length; i++)
  44. canA.add(cancellingPredsA[i]);
  45. return canA;
  46. } // end of static method loadCanA
  47. static ArrayList<Object> loadCanB() {
  48. ArrayList<Object> canB = new ArrayList<Object>();
  49. for (int i=0; i < cancellingPredsB.length; i++)
  50. canB.add(cancellingPredsB[i]);
  51. return canB;
  52. } // end of static method loadCanB
  53. static ArrayList<Object> loadOppoA() {
  54. ArrayList<Object> oppoA = new ArrayList<Object>();
  55. for (int i=0; i < oppositePredsA.length; i++)
  56. oppoA.add(oppositePredsA[i]);
  57. return oppoA;
  58. } // end of static method loadOppoA
  59. static ArrayList<Object> loadOppoB() {
  60. ArrayList<Object> oppoB = new ArrayList<Object>();
  61. for (int i=0; i < oppositePredsB.length; i++)
  62. oppoB.add(oppositePredsB[i]);
  63. return oppoB;
  64. } // end of static method loadOppoB
  65. static ArrayList<Object> loadGenPreds() {
  66. ArrayList<Object> gen = new ArrayList<Object>();
  67. for (int i=0; i < generalPreds.length; i++)
  68. gen.add(generalPreds[i]);
  69. return gen;
  70. } // end of static method loadGenPreds
  71. static void assignKinTerm(String kinTm, Individual ind, ClauseBody cb, boolean fillIn, Oracle orca) {
  72. // if the EgoNum on cb has been assigned, append it to the kinterm in parens
  73. String suffix = (cb.egoNum == -99 ? "" : "(" + cb.egoNum + ")"),
  74. histItem = kinTm + suffix + ":" + cb.seqNmbr + (fillIn ? "&" : ""),
  75. kinTerm = (Context.simulation
  76. ? cb.ktd.domTh.addNoise(kinTm, orca, Context.classNoise, Context.spellingNoise)
  77. : kinTm);
  78. if (kinTm.equals("Ego") || kinTerm.equals("Ego")) {
  79. Context.breakpoint();
  80. }
  81. ind.nameHistory.add(histItem);
  82. ArrayList<Object> termList = (DomainTheory.addrTerms ? ind.node.kinTermsAddr : ind.node.kinTermsRef),
  83. termListExt = (DomainTheory.addrTerms ? ind.node.extKinTermsAddr : ind.node.extKinTermsRef);
  84. if (termList.contains(kinTerm) || termListExt.contains(kinTerm)) {
  85. if (!fillIn) {
  86. cb.markDuplication(kinTerm, ind);
  87. }
  88. return; // we're not the first to conclude that this person has that relationship to Ego
  89. } // end of if-ind.termList.contains(kinTerm)
  90. if (cb.flags.contains("chooseLast") && !fillIn) {
  91. return; // must wait until all creation is done before assigning
  92. }
  93. if (cb.flags.contains("ext")) {
  94. termListExt.add(kinTerm);
  95. } else {
  96. termList.add(kinTerm);
  97. }
  98. ind.node.ktSuffix = suffix;
  99. if (cb.genderOfAlter.equals("?")) {
  100. ind.hasGenderNeutralKinTerm = true;
  101. }
  102. ind.node.setLevel(cb.level);
  103. return;
  104. } // end of method assignKinTerm
  105. /** Make a copy of this Literal, containing a list of copies of its args.
  106. @return a clone of this Literal.
  107. */
  108. public Argument copy() {
  109. Predicate newPred = new Predicate(predicate.name, predicate.category);
  110. ArrayList<Object> newArgs = new ArrayList<Object>();
  111. for (int i=0; i < args.size(); i++)
  112. newArgs.add(((Argument)args.get(i)).copy());
  113. Literal newLit = new Literal(newPred, newArgs);
  114. return newLit;
  115. } // end of method copy()
  116. /** Any other Literal is equivalent to this one if the predicate names match, the arg lists are the same
  117. length, and each arg is of the same type and has the same name. Recurse on any args that are Literals.
  118. @param other is the other Literal to be compared for equality
  119. @return true if all the above conditions are met; false otherwise.
  120. */
  121. public boolean isEquivalent(Literal other) {
  122. if (! predicate.name.equals(other.predicate.name)) return false;
  123. if (args.size() != other.args.size()) return false;
  124. Argument arg1, arg2;
  125. for (int i=0; i < args.size(); i++)
  126. if (args.get(i).getClass() != other.args.get(i).getClass()) return false;
  127. if (predicate.name.equals("not")) { // its args must be literals
  128. Literal negLit1, negLit2;
  129. for (int i=0; i < args.size(); i++) {
  130. negLit1 = (Literal)args.get(i);
  131. negLit2 = (Literal)other.args.get(i);
  132. if (! negLit1.isEquivalent(negLit2)) return false;
  133. } // end of loop thru args
  134. } else { // it's not a negated liteal
  135. for (int i=0; i < args.size(); i++) {
  136. arg1 = (Argument)args.get(i);
  137. arg2 = (Argument)other.args.get(i);
  138. if (! arg1.argName.equals(arg2.argName)) return false;
  139. } // end of loop thru args
  140. } // end of its-not-negated
  141. return true;
  142. } // end of method isEquivalent
  143. /** Make a string that replicates the form of this Literal when it was parsed.
  144. For example: 'parent(Alter,Ego)'
  145. @return a String replica.
  146. */
  147. public String toString() {
  148. String ar = "(";
  149. for (int i = 0; i < args.size(); i++) {
  150. ar += args.get(i);
  151. if (i < (args.size() - 1)) {
  152. ar += ", ";
  153. }
  154. } // end of for i from 0 to args.size()
  155. return predicate.name + ar + ")";
  156. } // end of toString method to override the default
  157. String toXML(String baseSpacer) {
  158. String s = baseSpacer + "<literal> \n";
  159. s += baseSpacer + "\t<predicate>" + predicate.name + "</predicate>\n";
  160. s += baseSpacer + "\t<arg-list>\n";
  161. for (int i = 0; i < args.size(); i++) {
  162. Argument arg = (Argument)args.get(i);
  163. s += arg.toXML(baseSpacer + "\t\t");
  164. }
  165. s += baseSpacer + "\t</arg-list>\n";
  166. s += baseSpacer + "</literal>";
  167. return s;
  168. }
  169. String toSILKString(String baseSpacer) {
  170. String s = baseSpacer + "<literal> \n";
  171. s += baseSpacer + "\t<predicate>" + predicate.name + "</predicate>\n";
  172. s += baseSpacer + "\t<arg-list>\n";
  173. for (int i = 0; i < args.size(); i++) {
  174. Argument arg = (Argument)args.get(i);
  175. s += arg.toSILKString(baseSpacer + "\t\t");
  176. }
  177. s += baseSpacer + "\t</arg-list>\n";
  178. s += baseSpacer + "</literal>";
  179. return s;
  180. }
  181. public Literal mergeWith(Literal lit2) {
  182. int index1 = cancelPredsA.indexOf(predicate.name),
  183. index2 = cancelPredsB.indexOf(lit2.predicate.name);
  184. if (index1 == index2 && index1 > -1) {
  185. return new Literal(new Predicate("omit"));
  186. }
  187. index1 = oppoPredsA.indexOf(predicate.name);
  188. index2 = oppoPredsB.indexOf(lit2.predicate.name);
  189. if (index1 == index2 && index1 > -1) {
  190. Literal newLit = (Literal) copy();
  191. Predicate newPred = new Predicate((String) genPreds.get(index1), new CulturalCategory());
  192. newLit.predicate = newPred;
  193. return newLit;
  194. }
  195. return null;
  196. } // end of method mergeWith
  197. public void countArgs(ArrayList<Object> firstMention, ArrayList<Object> otherMentions) {
  198. // Count the args in this Literal, using the passed in lists of previously-seen args.
  199. Argument thisArg;
  200. for (int i=0; i < args.size(); i++) {
  201. thisArg = (Argument)args.get(i);
  202. if (thisArg instanceof Literal) ((Literal)thisArg).countArgs(firstMention, otherMentions);
  203. else if (thisArg instanceof Variable) { // includes Variables and MathVariables
  204. String nam = thisArg.argName;
  205. if (! firstMention.contains(nam)) firstMention.add(nam); // a first mention
  206. else if (! otherMentions.contains(nam)) otherMentions.add(nam); // subsequent mention
  207. } // end of thisArg is a Variable
  208. } // end of loop thru args
  209. } // end of method countArgs()
  210. public ArrayList<Object> lits2MiniStrings(ArrayList<Object> clauseSoFar) throws KSInternalErrorException {
  211. ArrayList<Object> miniLits = new ArrayList<Object>();
  212. String lastVarName = "";
  213. for (int i=0; i < clauseSoFar.size(); i++) {
  214. Literal lit = (Literal)clauseSoFar.get(i);
  215. if (! constraintPred(lit)) {
  216. String thisLit = DT_Abstract2.predToSymbol(lit.predicate.name) + "(";
  217. for (int j=0; j < lit.args.size(); j++) {
  218. String argNam = ((Argument)lit.args.get(j)).argName;
  219. thisLit += argNam;
  220. if (j < lit.args.size() -1) {
  221. thisLit += ",";
  222. lastVarName = argNam;
  223. }
  224. }
  225. thisLit += ")";
  226. miniLits.add(thisLit);
  227. }
  228. } // end of i-loop
  229. if (! lastVarName.equals("")) {
  230. for (int j=0; j < miniLits.size(); j++) {
  231. String miniLit = (String)miniLits.get(j);
  232. int arg0Start = miniLit.indexOf("(") +1,
  233. comma = miniLit.indexOf(","),
  234. arg1End = miniLit.indexOf(")");
  235. if (comma == -1) { // single arg
  236. String argNam = miniLit.substring(arg0Start, arg1End);
  237. if (argNam.equals(lastVarName)) { // Replace with 'Alter'
  238. String replacementLit = miniLit.substring(0, arg0Start) + "Alter)";
  239. miniLits.remove(j);
  240. miniLits.add(j, replacementLit);
  241. }
  242. }else { // multi-arg
  243. String arg0Nam = miniLit.substring(arg0Start, comma),
  244. arg1Nam = miniLit.substring(comma +1, arg1End);
  245. if (arg0Nam.equals(lastVarName)) { // replace 1st arg
  246. String replacementLit = miniLit.substring(0, arg0Start) + "Alter";
  247. replacementLit += miniLit.substring(comma);
  248. miniLits.remove(j);
  249. miniLits.add(j, replacementLit);
  250. }else if (arg1Nam.equals(lastVarName)) { // replace 2nd arg
  251. String replacementLit = miniLit.substring(0, comma +1) + "Alter)";
  252. miniLits.remove(j);
  253. miniLits.add(j, replacementLit);
  254. }
  255. } // end of multi-arg
  256. } // end of j-loop
  257. } // end of lastVar Name not blank
  258. return miniLits;
  259. } // end of method lits2MiniStrings
  260. public boolean constraintPred(Literal lit) {
  261. String name = lit.predicate.name;
  262. if (name.equals("not") || name.equals("equal") || name.equals("male") || name.equals("female") ||
  263. name.equals("dead") || name.equals("divorced") || name.equals("elder") || name.equals("younger") ||
  264. name.equals("gender") || name.equals("lessThan") || name.equals("greaterThan") || name.equals("lessOrEql") ||
  265. name.equals("greaterOrEql") || name.equals("contains") || name.equals("allowCreation"))
  266. return true;
  267. else return false;
  268. } // end of method constraintPred
  269. public int computeLevel(String pcStr) throws KSInternalErrorException {
  270. int level = 0, ndx;
  271. char ch;
  272. char[] symbol = " ".toCharArray(); // 6 blanks
  273. symbol[0] = pcStr.charAt(0);
  274. if ((! Character.isUpperCase(symbol[0])) && (symbol[0] != '*')) // All symbols begin with cap or asterisk.
  275. throw new KSInternalErrorException("In LitAbs1.computeLevel: PC String started with non-capital letter");
  276. String result = "";
  277. int curr = 1;
  278. for (int i=1; i < pcStr.length(); i++) {
  279. ch = pcStr.charAt(i);
  280. if (Character.isUpperCase(ch) || (ch == '*') || (ch == '_')) {
  281. result = new String(symbol).trim();
  282. ndx = DT_Abstract2.kinTypeSymbols.indexOf(result);
  283. if (ndx < 5) level--;
  284. else if (ndx > 4 && ndx < 10) level++;
  285. symbol = " ".toCharArray();
  286. curr = 0;
  287. } // end of processing completed symbol
  288. symbol[curr++] = ch;
  289. } // end of loop thru chars in pcStr
  290. result = new String(symbol).trim();
  291. ndx = DT_Abstract2.kinTypeSymbols.indexOf(result);
  292. if (ndx < 5) level--;
  293. else if (ndx > 4 && ndx < 10) level++;
  294. return level;
  295. } // end of method computeLevel
  296. /** Expand this literal into the (multiple) primitive clause(s) which it represents.
  297. Only the primitive literal "not()" may have literals as arguments. If this assumption is
  298. violated, an exception is thrown.
  299. @param hypo the context from which this clause came.
  300. @param clauseSoFar a list of the expanded literals created before the current literal.
  301. @param remainingLits the literals remaining to be expanded.
  302. @param expandedDefs the list of expandedDefs to which we will add the finished product(s).
  303. @param save4Last the list of general negated constraints we'll process last.
  304. @param marker a StackMarkerObj holding the state of a recursive expansion (i.e. how many levels deep
  305. we are on which predicate). We push it onto the stack (remainingLits) behind the
  306. expansion of a non-primitive predicate, so that we can re-set our state to that after
  307. we finish expanding this predicate.
  308. @param origCB the original (non-expanded) clause we are expanding.
  309. @param path a trace of the expansion path followed in generating the current clauseSoFar.
  310. @throws KSBadHornClauseException if an invalid condidiotn is encountered.
  311. */
  312. public void expand(Context hypo, ArrayList<Object> clauseSoFar, ArrayList<Object> remainingLits, ArrayList<Object> expandedDefs,
  313. ArrayList<Object> save4Last, StackMarkerObj marker, ClauseBody origCB, ArrayList<Object> path)
  314. throws KSBadHornClauseException, KSInternalErrorException {
  315. /* DeBug code, for tracing causes of OutOfMemoryErrors when mutually-recursive definitions get too hairy.
  316. if (Context.breakFlag) {
  317. System.out.print("\n\nSerial# " + debugSerial++ + "\n\tCSF = \t");
  318. for (int i=0; i < clauseSoFar.size(); i++) System.out.print(clauseSoFar.get(i) + ", ");
  319. System.out.print("\n\tExpanding: " + this);
  320. System.out.print("\n\tRemLits = ");
  321. for (int i=0; i < remainingLits.size(); i++) System.out.print(remainingLits.get(i) + ", ");
  322. System.out.print("\n\tParam marker = " + marker);
  323. System.out.print("\n\tPath = ");
  324. for (int i=0; i < path.size(); i++) System.out.print(path.get(i) + ", ");
  325. System.out.println();
  326. // if (predicate.name.equals("not")) Context.breakpoint();
  327. }
  328. */
  329. if (clauseSoFar.size() >= 8 && clauseSoFar.size() % 4 == 0) { // Getting pretty big. Ck for size limit.
  330. try {
  331. ArrayList<Object> miniPreds = lits2MiniStrings(clauseSoFar),
  332. reducedPCStr = origCB.pcStringReduction(miniPreds, "Ego", "Alter", true);
  333. String redString = ClauseBody.sumStr(reducedPCStr);
  334. int stringDist = Math.min(Math.max((redString.length() / 2) - 1, 0), Library.ClauseCounts.maxDist);
  335. if (stringDist > Library.maxExpansionStringDist)
  336. return;
  337. int alterLevel = Math.abs(computeLevel(redString));
  338. if (alterLevel > Library.maxLevelForExpansion)
  339. return;
  340. }catch(KSInternalErrorException iex) { if (clauseSoFar.size() >= 16) return; }
  341. } // end of check for expansion limits
  342. if (predicate.category instanceof PrimitiveCategory) {
  343. // test the assumption that no args are Literals
  344. for (int i=0; i < args.size(); i++)
  345. if (((Argument)args.get(i) instanceof Literal) && (! predicate.name.equals("not")))
  346. throw new KSBadHornClauseException("A predicate other than 'not' had a Literal as an argument; Not Allowed\n");
  347. try {
  348. if ((! predicate.name.equals("not")) ||
  349. ((args.size() == 1) && (((Literal)args.get(0)).predicate.category instanceof PrimitiveCategory)))
  350. clauseSoFar.add(new Literal(predicate, args));
  351. else save4Last.add(this); // must be 'not' with multiple arg(s) or arg0 is non-primitive
  352. // That was easy. Now recurse on any remaining literals.
  353. if (remainingLits.isEmpty())
  354. finishExpansion(hypo, clauseSoFar, origCB, expandedDefs, save4Last, path);
  355. else { // remLits not empty. Pop & recurse
  356. StackMarkerObj newMarker = (StackMarkerObj)marker.copy(); // Use copies, so recursive calls don't increment the counts in marker
  357. Argument remLitArg = (Argument)remainingLits.get(0);
  358. remainingLits.remove(0); // pop it off remLits
  359. while (remLitArg.argType.equals("StackMarkerObj")) {
  360. newMarker = (StackMarkerObj)((StackMarkerObj)remLitArg).copy(); // restore old marker state
  361. remLitArg = (Argument)remainingLits.get(0);
  362. remainingLits.remove(0); // pop it off remLits
  363. } // end of while-it's-a-stack-marker
  364. Literal nextLit = (Literal)remLitArg;
  365. nextLit.expand(hypo, clauseSoFar, remainingLits, expandedDefs, save4Last, newMarker, origCB, path);
  366. } // end of RemLits was not empty
  367. }catch(ClassCastException exc) {
  368. throw new KSBadHornClauseException("The predicate 'not' was used with an argument that wasn't a Literal\n" + exc); }
  369. }else { // it's a non-primitive predicate
  370. int lvl = 0;
  371. boolean internalRecursFlag = false;
  372. KinTermDef ktd = (KinTermDef)DomainTheory.current.theory.get(predicate.name);
  373. if (ktd == null) // try both locations before giving up
  374. ktd = (KinTermDef)origCB.ktd.domTh.theory.get(predicate.name);
  375. if (ktd == null)
  376. throw new KSBadHornClauseException("Undefined predicate '" + predicate.name + "' used in a definition.");
  377. Literal head = ktd.clauseHead;
  378. ArrayList<Object> subDefs = ktd.definitions; // subDefs is a list of the ClauseBodies defining this predicate
  379. // Check for recursive level exceeded. Post this for future checks on StackMarkerObj.
  380. if (marker.kinTermLst.contains(predicate.name)) { // we've discovered a recursive definition
  381. int position = marker.kinTermLst.indexOf(predicate.name);
  382. internalRecursFlag = true;
  383. lvl = ((Integer)marker.recursLvlLst.get(position)).intValue() + 1;
  384. marker.recursLvlLst.set(position, new Integer(lvl));
  385. } // end of if-this-is-a-recursive-clause
  386. if ((! internalRecursFlag) || (lvl <= DomainTheory.current.levelsOfRecursion)) {
  387. // we've not yet exceeded the limit for recursive expansions
  388. for (int i=0; i < subDefs.size(); i++) {
  389. ClauseBody cb = (ClauseBody)subDefs.get(i); // the i-th ClauseBody in def'n
  390. ArrayList<Object> oldVarName = new ArrayList<Object>(), newVarName = new ArrayList<Object>(),
  391. newPath = new ArrayList<Object>(path);
  392. ClauseBody newcb = argSubst(head, args, cb, oldVarName, newVarName);
  393. // argSubst makes a copy w/ arg substitutions
  394. newPath.add(predicate.name + ":" + i);
  395. ArrayList<Object> newClauseSoFar = new ArrayList<Object>(), newSave4Last = new ArrayList<Object>(save4Last);
  396. for (int k=0; k < clauseSoFar.size(); k++) // Make a deep copy of clauseSoFar
  397. newClauseSoFar.add( ((Literal)clauseSoFar.get(k)).copy() );
  398. ArrayList<Object> newKinTermLst = new ArrayList<Object>(marker.kinTermLst),
  399. newRecursLvlLst = new ArrayList<Object>(marker.recursLvlLst);
  400. if (! internalRecursFlag) { // this is the first time we've encountered this predicate.
  401. newKinTermLst.add(predicate.name);
  402. newRecursLvlLst.add(new Integer(0));
  403. } // end of if-this-is-a-new-predicate
  404. StackMarkerObj newMarker = new StackMarkerObj(newKinTermLst, newRecursLvlLst);
  405. Literal nextLit = (Literal)newcb.body.get(0);
  406. ArrayList<Object> newRemainingLits = new ArrayList<Object>(newcb.body.subList(1, newcb.body.size()));
  407. if (remainingLits.size() > 0) {
  408. newRemainingLits.add(marker); // push a copy of the incoming marker onto remLits
  409. newRemainingLits.addAll(remainingLits); // followed by prior remainingLits
  410. } // end of if-remLits-is-not-empty
  411. ClauseBody newOrigCB = origCB.copy();
  412. newOrigCB.flags.addAll(cb.flags);
  413. nextLit.expand(hypo, newClauseSoFar, newRemainingLits, expandedDefs, newSave4Last,
  414. newMarker, newOrigCB, newPath); // recurse on nextLit
  415. } // end of for-i=each-clauseBody-in-subDefs
  416. } // end of we-have-not-yet-exceeded-the-limit-for-recursive-expansions
  417. } // end of else-it's-not-primitive
  418. return;
  419. } // end of method expand
  420. public void finishExpansion(Context hypo, ArrayList<Object> clauseSoFar, ClauseBody origCB, ArrayList<Object> expandedDefs,
  421. ArrayList<Object> save4Last, ArrayList<Object> path) throws KSBadHornClauseException, KSInternalErrorException {
  422. ArrayList<Object> expNegConstraints = new ArrayList<Object>(), subPaths = new ArrayList<Object>(), subPath;
  423. if (save4Last.size() > 0)
  424. neg_expand(hypo, save4Last, expNegConstraints, origCB, subPaths);
  425. ClauseBody cb = new ClauseBody();
  426. cb.ktd = origCB.ktd;
  427. Literal lit;
  428. for (int i=0; i < clauseSoFar.size(); i++) {
  429. lit = (Literal)clauseSoFar.get(i);
  430. cb.addLiteral(lit);
  431. } // end of for i = each lit in clauseSoFar
  432. cb.flags = origCB.flags;
  433. Iterator newLitIter = expNegConstraints.iterator();
  434. cb.expansionPath.addAll(path);
  435. for (int j=0; j < subPaths.size(); j++) {
  436. subPath = (ArrayList<Object>)subPaths.get(j);
  437. cb.expansionPath.addAll(subPath);
  438. } // end of loop thru ALists of Strings in subPaths
  439. while (newLitIter.hasNext())
  440. cb.addLiteral((Literal)newLitIter.next());
  441. expandedDefs.add(cb);
  442. } // end of method finishExpansion
  443. /** Expand the negated predicates (e.g. 'not(parents(A,B), parents(B,C))' ) found in save4Last and
  444. build a logically equivalent group of negated primitive predicates in expNegConstraints.
  445. <p>
  446. NOTE: If we are expanding the literal 'not(alpha(A,B))' and alpha is defined as beta or gamma, then
  447. the logical equivalent of 'not(alpha(A,B))' is 'not(beta(A,B)) AND not(gamma(A,B))'. The meaning of a
  448. ClauseBody is "a conjunction of literals" i.e. each literal in a clause must be true for the clause to
  449. be true. Therefore, we build a single ClauseBody from each negated predicate.
  450. @param hypo the context from which this clause came.
  451. @param save4Last a list of the negated literals to be expanded.
  452. @param expNegConstraints a list to receive the expanded negated literals.
  453. @param origCB the original (non-expanded) clause we are expanding.
  454. @param subPaths a trace of the expansion path followed in expanding the negated literals.
  455. */
  456. public void neg_expand(Context hypo, ArrayList<Object> save4Last, ArrayList<Object> expNegConstraints,
  457. ClauseBody origCB, ArrayList<Object> subPaths) throws KSBadHornClauseException, KSInternalErrorException {
  458. Iterator negIter = save4Last.iterator();
  459. Literal negLit;
  460. while (negIter.hasNext()) {
  461. negLit = (Literal)negIter.next();
  462. if (! negLit.predicate.name.equals("not"))
  463. throw new KSBadHornClauseException("Internal Error: in Literal.expand, predicate other than 'not'\n" +
  464. "found in 'save4Last.' File Bug Report!");
  465. ArrayList<Object> remLits = new ArrayList<Object>(), expDefs = new ArrayList<Object>(), negPath = new ArrayList<Object>();
  466. StackMarkerObj marker = new StackMarkerObj(new ArrayList<Object>(), new ArrayList<Object>());
  467. negPath.add("(not:");
  468. Literal firstLit = (Literal)negLit.args.get(0);
  469. remLits.addAll(negLit.args.subList(1,negLit.args.size()));
  470. // expand will build 1 or more all-primitive ClauseBodies in expDefs
  471. try {
  472. firstLit.expand(hypo, new ArrayList<Object>(), remLits, expDefs, new ArrayList<Object>(), marker, origCB, negPath);
  473. for (int i=0; i < expDefs.size(); i++) {
  474. ClauseBody xCB = (ClauseBody)expDefs.get(i);
  475. Literal newLit = new Literal(new Predicate("not"));
  476. newLit.args = xCB.body;
  477. expNegConstraints.add(newLit);
  478. xCB.expansionPath.add(")");
  479. subPaths.add(xCB.expansionPath);
  480. } // end of loop thru CBs returned by expand
  481. }catch(KSBadHornClauseException bhc)
  482. { throw new KSBadHornClauseException("While in Lit.Neg_Expand:\n" + bhc); }
  483. } // end of loop thru all negated literals in save4Last
  484. } // end of method neg_expand
  485. ClauseBody argSubst(Literal subDefHead, ArrayList<Object> currPredArgs, ClauseBody subDef, ArrayList<Object> oldVarName, ArrayList<Object> newVarName) {
  486. // subDefHead is the literal at the head of this Horn Clause e.g. uncle(Alter,Ego) :- ...
  487. // currPredArgs holds the names of the args of the literal we're expanding e.g. uncle(X, P)
  488. // subDef.body is the list of literals making up one definition of the literal we're expanding
  489. // It contains the arguments that we must re-name.
  490. // STRATEGY: If the definition is: uncle(Alter,Ego) :- parent(P,Ego), sibling(Alter,P), male(Alter).
  491. // and we are expanding a literal "uncle(X, P)"
  492. // We want to change each occurrence of "Alter" in the definition to "X" and likewise "Ego" -> "P"
  493. // Furthermore, any other "free variables" occurring in the definition must be given new names that
  494. // are guaranteed unique so they won't accidently duplicate some other variable in our literal
  495. // e.g. "P" -> "PQ37"
  496. boolean flag;
  497. Literal oldLit, newLit;
  498. Predicate pred;
  499. Argument oldArg, newArg;
  500. ArrayList<Object> newArgs;
  501. ClauseBody newcb = new ClauseBody();
  502. newcb.ktd = subDef.ktd;
  503. for (int i=0; i < subDef.body.size(); i++) {
  504. oldLit = (Literal)subDef.body.get(i);
  505. pred = (Predicate)oldLit.predicate.copy();
  506. newArgs = new ArrayList<Object>();
  507. for (int j=0; j < oldLit.args.size(); j++) {
  508. oldArg = (Argument)oldLit.args.get(j);
  509. newArg = oldArg;
  510. if (oldArg.argType.equals("Constant")) // make an exact copy
  511. newArg = new Constant(oldArg.argName);
  512. else if (oldArg.argType.equals("ArgString")) // make an exact copy
  513. newArg = ((ArgString)oldArg).copy();
  514. else if (oldArg instanceof Variable) { // do argument re-naming
  515. flag = false;
  516. for (int k=0; k < subDefHead.args.size(); k++) {
  517. if (oldArg.argName.equals(((Argument)subDefHead.args.get(k)).argName)) {
  518. flag = true;
  519. newArg = new Variable(((Argument)currPredArgs.get(k)).argName);
  520. } // end of if-argnames-are-equal
  521. } // end of for k=each-argname-in-subDefHeadArgs
  522. for (int h=0; h < oldVarName.size(); h++) {
  523. if (oldArg.argName.equals(oldVarName.get(h))) {
  524. flag = true;
  525. newArg = new Variable((String)newVarName.get(h));
  526. }
  527. } // end of for h=each-prior-substitution
  528. if (! flag) { // this argName not in the subDef clause head or prior subst'ns
  529. // we must give this variable a new, unique name
  530. oldVarName.add(oldArg.argName);
  531. String newName = genUniqueArgName(oldArg.argName);
  532. newVarName.add(newName);
  533. newArg = new Variable(newName);
  534. } // end of if-not-flag
  535. } // end of if-this-is-a-Variable
  536. else if (oldArg.argType.equals("Literal")) {
  537. // we'll recurse on this literal to make arg substitutions
  538. ClauseBody newSubDef = new ClauseBody();
  539. newSubDef.ktd = subDef.ktd;
  540. newSubDef.addLiteral((Literal)oldArg);
  541. ClauseBody result = argSubst(subDefHead, currPredArgs, newSubDef, oldVarName, newVarName);
  542. newArg = (Literal)result.body.get(0); // we know we'll get 1 Literal back
  543. } // end of if-this-is-a-Literal
  544. newArgs.add(newArg);
  545. } // end of for j=each-argument-in-this-literal
  546. newLit = new Literal(pred, newArgs);
  547. newcb.body.add(newLit);
  548. } // end of for i=each-literal-in-subDef
  549. return newcb;
  550. } // end of method argSubst
  551. String genUniqueArgName(String oldName) {
  552. return oldName + "%" + serializer++;
  553. } // end of method genUniqueArgName
  554. void unifyVariables(TreeMap bindery, ArrayList<Object> remLits, Counter cntr) throws KSConstraintInconsistency {
  555. // Examine each argument of this literal. If an argname has appeared before in the enclosing clausebody,
  556. // it will be listed in the bindery -- re-use the Variable object in the bindery.
  557. // If this argName has NOT appeared before, make a NEW Variable & post it to the bindery.
  558. // Be sure to get "clean" new copies of arguments (without any values carried over from prior uses of this literal)
  559. // If any arg is another literal, recurse depth-first on that lit, then proceed.
  560. // When done, pass the updated bindery to the next lit of the remainingLits.
  561. Argument arg, boundArg, newArg;
  562. // if (Context.breakFlag) Context.breakpoint();
  563. for (int i=0; i < args.size(); i++) {
  564. arg = (Argument)args.get(i);
  565. if ((arg instanceof Variable) || (arg instanceof Constant)) {
  566. boundArg = (Argument)bindery.get(arg.argName);
  567. if (boundArg != null) args.set(i, boundArg);
  568. else {
  569. if ((arg instanceof Variable) && (predicate.category instanceof MathCategory))
  570. newArg = new MathVariable((Variable)arg);
  571. else if ((arg instanceof Variable)
  572. && ((predicate.name.substring(0, 1).equals("*")) && (i == 0))) {
  573. // arg0 of a *-prop is either a Personal Variable or a MathVariable
  574. UserDefinedProperty udp = (UserDefinedProperty)Context.current.userDefinedProperties.get(predicate.name);
  575. if (udp.singleValue && (udp.typ.equals("individual"))) newArg = arg.copy();
  576. // Multi-person = a list, which needs a MathVariable. Single person = an individual
  577. else newArg = new MathVariable((Variable)arg);
  578. newArg.valueType = udp.typ;
  579. }
  580. else newArg = arg.copy();
  581. if (arg.argName.equals("Ego")) newArg.argName = stdEgo; // use standard string (static)
  582. else if (arg.argName.equals("Alter")) newArg.argName = stdAlter; // ditto
  583. else newArg.argName = argCodes[cntr.incr()]; // arbitrary codes for interior variables
  584. if (newArg instanceof Variable) // Don't wipe out the value of a constant
  585. newArg.clearVal(); // Make clean copy (no values) of Variables
  586. bindery.put(arg.argName, newArg);
  587. args.set(i, newArg);
  588. } // end of else-vari-was-null
  589. } // end of its-a-Variable
  590. else if (arg.argType.equals("Literal"))
  591. ((Literal)arg).unifyVariables(bindery, null, cntr);
  592. } // end of loop thru args
  593. // TYPE-CHECK THE ARGUMENTS OF MATHCATS, STAR-PREDICATES, AND EQUAL
  594. Argument arg0 = (Argument)args.get(0), arg1 = null;
  595. if (args.size() > 1) arg1 = (Argument)args.get(1); // All have 2 args
  596. if (predicate.name.substring(0, 1).equals("*")) {
  597. UserDefinedProperty udp = (UserDefinedProperty)Context.current.userDefinedProperties.get(predicate.name);
  598. if (arg0.valueType.equals(udp.typ)) { // OK. Do nothing.
  599. }else if (arg0.valueType.equals("default")) {
  600. arg0.valueType = udp.typ;
  601. }else if ((arg0 instanceof Constant) && (arg0.valueType.equals("integer"))
  602. && (udp.typ.equals("float"))) {
  603. arg0.valueType = "float";
  604. Integer oldInt = (Integer)arg0.getVal().get(0);
  605. arg0.removeVal(oldInt);
  606. arg0.addVal(new Float(oldInt.toString()));
  607. }else {
  608. String msg = "UnifyVariables encountered '" + this + "' with conflicting value-types";
  609. throw new KSConstraintInconsistency(msg);
  610. }
  611. }else if ((predicate.category instanceof MathCategory)
  612. || (predicate.name.equals("equal")
  613. && ((arg0 instanceof MathVariable) || (arg0 instanceof Constant))
  614. && ((arg1 instanceof MathVariable) || (arg1 instanceof Constant)))) {
  615. if (arg0.valueType.equals(arg1.valueType)) { // OK. Do nothing.
  616. }else if ((arg0 instanceof Constant) || (arg1 instanceof Constant)) {
  617. // Allow a Constant integer like '5' to be used instead of '5.0' with Float-valued MathVars or *-Preds
  618. Variable vee = null;
  619. Constant konst = null; // One of these args is a Constant
  620. if (arg0 instanceof Constant) {
  621. konst = (Constant)arg0;
  622. vee = (Variable)arg1;
  623. }else {
  624. konst = (Constant)arg1;
  625. vee = (Variable)arg0;
  626. }
  627. if ((vee.valueType.equals("float")) && (konst.valueType.equals("integer"))) {
  628. konst.valueType = "float";
  629. Integer oldInt = (Integer)konst.getVal().get(0);
  630. konst.removeVal(oldInt);
  631. konst.addVal(new Float(oldInt.toString()));
  632. }else if (! konst.valueType.equals(vee.valueType)) { // Ooops - type coercion didn't work - throw Exception.
  633. String msg = "UnifyVariables encountered '" + this + "' with conflicting value-types";
  634. throw new KSConstraintInconsistency(msg);
  635. }
  636. }else { // must be 2 MathVars
  637. if (arg0.valueType.equals("default") && (! arg1.valueType.equals("default"))) { // Propogate types if needed.
  638. arg0.valueType = arg1.valueType; // If this results in a later clash,
  639. }else if (arg1.valueType.equals("default") && (! arg0.valueType.equals("default"))) { // it will throw Exception then.
  640. arg1.valueType = arg0.valueType;}
  641. }
  642. }else if ((arg1 == null) || (predicate.name.equals("not"))
  643. || (arg0.valueType.equals(arg1.valueType))) { // OK. Do nothing.
  644. }else if (arg0.valueType.equals("default") && (! arg1.valueType.equals("default"))) { // Propogate types if needed.
  645. arg0.valueType = arg1.valueType; // If this results in a later clash,
  646. }else if (arg1.valueType.equals("default") && (! arg0.valueType.equals("default"))) { // it will throw Exception then.
  647. arg1.valueType = arg0.valueType;
  648. }else { // Type coercion not appropriate, and type mis-match. Throw Exception.
  649. String msg = "UnifyVariables encountered '" + this + "' with conflicting value-types";
  650. throw new KSConstraintInconsistency(msg);
  651. }
  652. if ((remLits != null) && (remLits.size() > 0)) {
  653. Literal lit = (Literal)remLits.get(0);
  654. ArrayList<Object> newRemLits = new ArrayList<Object>(remLits.subList(1, remLits.size()));
  655. lit.unifyVariables(bindery, newRemLits, cntr);
  656. } // end of remList-isn't-empty
  657. return;
  658. } // end of method unifyVariables
  659. /** Begin (or add to) the extraction of gender, equality etc constraints. If conflicting gender constraints
  660. are found for Ego's sex, return false (it's possible). If conflicts are found for anyone else, throw an exception.
  661. Death & divorce constraints on a {@link ConstraintObj} are single-valued. The others have lists of values.
  662. If the user has defined any properties (constraints), those must have names beginning with '*'. They are
  663. recorded as userDefined constraints.
  664. The negated constraints are unique; they apply to the entire clause, not to any one {@link Variable};
  665. each negated constraint is a ClauseBody.
  666. @param egoGender the gender of Ego: "M" or "F".
  667. @param constraints a (perhaps empty) ConstraintObj holding the constraints extracted thus far.
  668. @param genderStuff a (perhaps empty) ArrayList<Object> of Literals relevant to gender.
  669. @param starStuff a (perhaps empty) ArrayList<Object> of Literals relevant to User-Defined (or "*-") predicates.
  670. @throws KSBadHornClauseException if an invalid number of args is supplied for a predicate
  671. @throws KSConstraintInconsistency if a contradictory constraints are encountered (e.g. male(X) and female(X))
  672. @return false if any conflicts are discovered; true otherwise.
  673. */
  674. public boolean constraintCheck(String egoGender, ConstraintObj constraints, ArrayList<Object> genderStuff, ArrayList<Object> starStuff)
  675. throws KSBadHornClauseException, KSConstraintInconsistency {
  676. // First validate the arity of the predicates
  677. if ((args.isEmpty()) && (! (predicate.name.equals("allowCreation"))))
  678. throw new KSBadHornClauseException("Incorrect number of args for " + this);
  679. if ((args.size() == 1) &&
  680. (! ((predicate.name.equals("male")) || (predicate.name.equals("female")) ||
  681. (predicate.name.equals("dead")) || (predicate.name.equals("divorced")) ||
  682. (predicate.name.equals("not")))))
  683. throw new KSBadHornClauseException("Incorrect number of args for " + this);
  684. if ((args.size() == 2) && ((predicate.name.equals("male")) || (predicate.name.equals("female")) ||
  685. (predicate.name.equals("dead"))))
  686. throw new KSBadHornClauseException("Incorrect number of args for " + this);
  687. if ((args.size() > 2) && (! predicate.name.equals("not")))
  688. throw new KSBadHornClauseException("Incorrect number of args for " + this);
  689. // Next, extract gender implications & check 'em
  690. String argName, otherName, oldConstraint, otherConstraint;
  691. if ((predicate.name.equals("father")) || (predicate.name.equals("son"))
  692. || (predicate.name.equals("male")) || (predicate.name.equals("husband"))) {
  693. // All imply arg0 is male. Pass that to our helpful assistant. Return of false means conflict.
  694. if (! (genderCheck(((Argument)args.get(0)).argName, "M", "F", constraints.gender)))
  695. throw new KSConstraintInconsistency("Conflicting gender constraints for " + ((Argument)args.get(0)).argName);
  696. ((Variable)args.get(0)).neuterOK = false;
  697. if (predicate.name.equals("husband")) // corrolary: wife is female
  698. if (! (genderCheck(((Argument)args.get(1)).argName, "F", "M", constraints.gender)))
  699. throw new KSConstraintInconsistency("Conflicting gender constraints for " + ((Argument)args.get(1)).argName);
  700. }
  701. else if ((predicate.name.equals("mother")) || (predicate.name.equals("daughter"))
  702. || (predicate.name.equals("female")) || (predicate.name.equals("wife"))) {
  703. // all imply arg0 is female
  704. if (! (genderCheck(((Argument)args.get(0)).argName, "F", "M", constraints.gender)))
  705. throw new KSConstraintInconsistency("Conflicting gender constraints for " + ((Argument)args.get(0)).argName);
  706. ((Variable)args.get(0)).neuterOK = false;
  707. if (predicate.name.equals("wife")) // corrolary: husband is male
  708. if (! (genderCheck(((Argument)args.get(1)).argName, "M", "F", constraints.gender)))
  709. throw new KSConstraintInconsistency("Conflicting gender constraints for " + ((Argument)args.get(1)).argName);
  710. }
  711. else if ((predicate.name.equals("spouse")) || ((predicate.name.equals("divorced")) && (args.size() == 2)))
  712. { // both have 2 args, both Variables
  713. String sp1 = ((Argument)args.get(0)).argName, sp2 = ((Argument)args.get(1)).argName;
  714. ArrayList<Object> sp1sex = (ArrayList<Object>)constraints.gender.get(sp1),
  715. sp2sex = (ArrayList<Object>)constraints.gender.get(sp2);
  716. if ((sp1sex == null) && (sp2sex == null)) {
  717. // No info on gender of either one -- can't take final action yet
  718. ArrayList<Object> sexList1 = new ArrayList<Object>(), sexList2 = new ArrayList<Object>();
  719. sexList1.add("Opposite of " + sp2);
  720. sexList2.add("Opposite of " + sp1);
  721. constraints.gender.put(sp1, sexList1);
  722. constraints.gender.put(sp2, sexList2);
  723. } // end of if-both-are-null
  724. else if (sp1sex == null) { // sp2 must have a list with specified sex or "Opposite X" etc.
  725. sp1sex = new ArrayList<Object>();
  726. if (sp2sex.contains("M")) sp1sex.add("F");
  727. else if (sp2sex.contains("F")) sp1sex.add("M");
  728. else sp1sex.add("Opposite of " + sp2);
  729. constraints.gender.put(sp1, sp1sex);
  730. } // end of else-if-sp1sex==null
  731. else { // sp1 must have a list with specified sex or "Opposite X"
  732. sp2sex = new ArrayList<Object>();
  733. if (sp1sex.contains("M")) sp2sex.add("F");
  734. else if (sp1sex.contains("F")) sp2sex.add("M");
  735. else sp2sex.add("Opposite of " + sp1);
  736. constraints.gender.put(sp2, sp2sex);
  737. } // end of else-sp1-is-specified
  738. } // end of else-if-pred==spouse
  739. else if ((predicate.name.equals("not")) && (args.size() == 1)) { // 'not' with 1 arg, a literal
  740. Literal negatedLit = (Literal)args.get(0);
  741. if (negatedLit.predicate.name.equals("male")) {
  742. if (! (genderCheck(((Argument)negatedLit.args.get(0)).argName, "F", "M", constraints.gender)))
  743. throw new KSConstraintInconsistency("Conflicting gender constraints for " + ((Argument)negatedLit.args.get(0)).argName);
  744. } // end of if-pred=not-male
  745. else if (negatedLit.predicate.name.equals("female")) {
  746. if (! (genderCheck(((Argument)negatedLit.args.get(0)).argName, "M", "F", constraints.gender)))
  747. throw new KSConstraintInconsistency("Conflicting gender constraints for " + ((Argument)negatedLit.args.get(0)).argName);
  748. } // end of if-pred=not-female
  749. else if (negatedLit.predicate.name.equals("dead"))
  750. constraints.death.put((((Argument)negatedLit.args.get(0)).argName), "alive");
  751. else if ((negatedLit.predicate.name.equals("divorced")) && (negatedLit.args.size() == 1))
  752. constraints.divorce.put((((Argument)negatedLit.args.get(0)).argName), "undivorced");
  753. else if (negatedLit.predicate.name.equals("equal")) {
  754. String arg0Name = ((Argument)negatedLit.args.get(0)).argName;
  755. String arg1Name = ((Argument)negatedLit.args.get(1)).argName;
  756. genderStuff.add(this);
  757. // If the 2 args to 'equal' are Variables (for persons) they don't belong in starStuff. Equal w/ 2 Constants is silly.
  758. // Ergo, if at least 1 of the args is a MathVariable, put it in starStuff
  759. if ((negatedLit.args.get(0) instanceof MathVariable) || (negatedLit.args.get(1) instanceof MathVariable))
  760. starStuff.add(this);
  761. // Add this inequality constraint, if not a duplicate.
  762. if (constraints.unEqual.get(arg0Name) == null) constraints.unEqual.put(arg0Name, new ArrayList<Object>());
  763. if (constraints.unEqual.get(arg1Name) == null) constraints.unEqual.put(arg1Name, new ArrayList<Object>());
  764. if (! (((ArrayList<Object>)constraints.unEqual.get(arg0Name)).contains(arg1Name)))
  765. ((ArrayList<Object>)constraints.unEqual.get(arg0Name)).add(arg1Name);
  766. if (! (((ArrayList<Object>)constraints.unEqual.get(arg1Name)).contains(arg0Name)))
  767. ((ArrayList<Object>)constraints.unEqual.get(arg1Name)).add(arg0Name);
  768. } // end of if-pred=not-equal
  769. else { // must be negation of a general-purpose predicate
  770. ClauseBody cb = new ClauseBody(negatedLit);
  771. constraints.negated.add(cb);
  772. } // end of must-be-negation-of-general-predicate
  773. } // end of else-if-pred==not-with-1-arg
  774. else if (predicate.name.equals("not")) { // 'not' with MORE than 1 arg. - all primitives
  775. Literal lit = (Literal)args.get(0); // This must be a general negation (expanded)
  776. ClauseBody cb = new ClauseBody(lit);
  777. for (int k=1; k < args.size(); k++) {
  778. lit = (Literal)args.get(k);
  779. cb.addLiteral(lit);
  780. } // end of for-k=each-literal
  781. constraints.negated.add(cb);
  782. } // end of else-if-pred==not-with-multi-args
  783. else if (predicate.name.equals("elder")) { // arg0 is older than arg1
  784. String arg0Name = ((Argument)args.get(0)).argName;
  785. String arg1Name = ((Argument)args.get(1)).argName;
  786. String constraint;
  787. constraint = "more than " + arg1Name;
  788. if (constraints.age.get(arg0Name) == null) constraints.age.put(arg0Name, new ArrayList<Object>());
  789. if (constraints.age.get(arg1Name) == null) constraints.age.put(arg1Name, new ArrayList<Object>());
  790. if (! (((ArrayList<Object>)constraints.age.get(arg0Name)).contains(constraint)))
  791. ((ArrayList<Object>)constraints.age.get(arg0Name)).add(constraint);
  792. constraint = "less than " + arg0Name;
  793. if (! (((ArrayList<Object>)constraints.age.get(arg1Name)).contains(constraint)))
  794. ((ArrayList<Object>)constraints.age.get(arg1Name)).add(constraint);
  795. } // end of if-pred=elder
  796. else if (predicate.name.equals("younger")) { // arg0 is younger than arg1
  797. String arg0Name = ((Argument)args.get(0)).argName;
  798. String arg1Name = ((Argument)args.get(1)).argName;
  799. String constraint;
  800. constraint = "less than " + arg1Name;
  801. if (constraints.age.get(arg0Name) == null) constraints.age.put(arg0Name, new ArrayList<Object>());
  802. if (constraints.age.get(arg1Name) == null) constraints.age.put(arg1Name, new ArrayList<Object>());
  803. if (! (((ArrayList<Object>)constraints.age.get(arg0Name)).contains(constraint)))
  804. ((ArrayList<Object>)constraints.age.get(arg0Name)).add(constraint);
  805. constraint = "more than " + arg0Name;
  806. if (! (((ArrayList<Object>)constraints.age.get(arg1Name)).contains(constraint)))
  807. ((ArrayList<Object>)constraints.age.get(arg1Name)).add(constraint);
  808. } // end of if-pred=younger
  809. else if (predicate.name.equals("allowCreation")) { // no args: a flag re: negated constraints
  810. constraints.allowCreation = true;
  811. } // end of if-pred=allowCreation
  812. else if (predicate.name.equals("dead")) { // arg0 is dead
  813. constraints.death.put((((Argument)args.get(0)).argName), "dead");
  814. } // end of if-pred=dead
  815. else if ((predicate.name.equals("divorced")) && (args.size() == 1)) {
  816. // arg0 is the only arg. He/she was divorced at least once.
  817. constraints.divorce.put((((Argument)args.get(0)).argName), "divorced");
  818. } // end of if-pred=divorced
  819. else if (predicate.name.equals("gender")) {
  820. ((Variable)args.get(1)).neuterOK = false; // any variable in a gender pred can't be neuter
  821. genderStuff.add(this);
  822. } // end of pred=gender
  823. // if it is a star-predicate or in the MathCategory, it will be handled in starStuff.
  824. else if (predicate.name.substring(0, 1).equals("*") || (predicate.category instanceof MathCategory))
  825. starStuff.add(this);
  826. // now check to see if we've generated a specification that contradicts Ego's known gender
  827. // unless ego.gender = "?" in which case anything goes
  828. ArrayList<Object> egoSpecList = (ArrayList<Object>)constraints.gender.get("Ego");
  829. String egoSpec;
  830. if (egoSpecList != null) {
  831. Iterator egoIter = egoSpecList.iterator();
  832. while (egoIter.hasNext()) {
  833. egoSpec = (String)egoIter.next();
  834. if ((! (egoGender.equals("?"))) && (egoSpec.indexOf("Same") == -1) &&
  835. (egoSpec.indexOf("Opposite") == -1) && (! (egoSpec.equals(egoGender))))
  836. return false;
  837. } // end of iteration-thru-gender-specs
  838. } // end of if-egoSpecList != null
  839. return true;
  840. } // end of method constraintCheck
  841. boolean genderCheck(String argName, String rightSex, String wrongSex, TreeMap gende

Large files files are truncated, but you can click here to view the full file