PageRenderTime 31ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/code/Literal.java

http://silkin.googlecode.com/
Java | 1020 lines | 817 code | 69 blank | 134 comment | 547 complexity | 5be374b7fdf3e2e0e42fcda3e005d6b7 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 class completes the definition of a Literal in Prolog syntax. Literals are the basic building blocks of
  5. Horn Clauses. They also are the level at which 90% of the action takes place in Example-Generation.
  6. <p>
  7. Because so many methods are defined at the Literal level, the code files are broken into 3 classes: LiteralAbstract1,
  8. LiteralAbstract2, and this one.
  9. @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
  10. */
  11. public class Literal extends LiteralAbstract2 {
  12. /** This zero-arg constructor is for use ONLY by Serialization or for 'dummy' literals. */
  13. public Literal() { super(); } // end of zero-arg constructor
  14. // We expect literals with 1 or more arguments (although allowCreation is a 0-arg predicate).
  15. /** Standard constructor with just the predicate supplied.
  16. @param pred the predicate of this Literal.
  17. */
  18. public Literal(Predicate pred) {
  19. super();
  20. predicate = pred;
  21. } // end of predicate-only constructor
  22. /** Standard constructor with the predicate + 1 argument supplied.
  23. @param pred the predicate of this Literal.
  24. @param arg0 the first argument of this Literal.
  25. */
  26. public Literal(Predicate pred, Argument arg0) {
  27. super();
  28. predicate = pred;
  29. args.add(arg0);
  30. } // end of 1-arg constructor
  31. /** Standard constructor with the predicate + 2 arguments supplied.
  32. @param pred the predicate of this Literal.
  33. @param arg0 the first argument of this Literal.
  34. @param arg1 the second argument of this Literal.
  35. */
  36. public Literal(Predicate pred, Argument arg0, Argument arg1) {
  37. super();
  38. predicate = pred;
  39. args.add(arg0);
  40. args.add(arg1);
  41. } // end of 2-arg constructor
  42. /** Standard constructor with the predicate + 3 arguments supplied.
  43. @param pred the predicate of this Literal.
  44. @param arg0 the first argument of this Literal.
  45. @param arg1 the second argument of this Literal.
  46. @param arg2 the third argument of this Literal.
  47. */
  48. public Literal(Predicate pred, Argument arg0, Argument arg1, Argument arg2) {
  49. super();
  50. args.add(arg0);
  51. args.add(arg1);
  52. args.add(arg2);
  53. } // end of 3-arg constructor
  54. /** Standard constructor with the predicate and an ArrayList<Object> of arguments.
  55. @param pred the predicate of this Literal.
  56. @param argArray the arguments of this Literal.
  57. */
  58. public Literal(Predicate pred, ArrayList<Object> argArray) {
  59. super();
  60. predicate = pred;
  61. for (int i=0; i < argArray.size(); i++)
  62. args.add(((Argument)argArray.get(i)).copy());
  63. } // end of argArray constructor
  64. public Object bindingVal() {
  65. return "WARNING: 'bindingVal()' was called on a Literal. Invalid call -- this String will wreak havoc & trigger Exceptions.";
  66. } // method bindingVal is required for all sub-classes of Argument. But it should NEVER be called on a Literal.
  67. public void reverseArgs() throws KSInternalErrorException {
  68. // Called only on lits where gender of args is unknown or elder/younger
  69. if (args.size() < 2) throw new KSInternalErrorException("ERROR: Called 'reverseArgs' on " + toString());
  70. Argument hold = (Argument)args.remove(0);
  71. args.add(1, hold);
  72. if (predicate.name.equals("elder")) predicate.name = "younger";
  73. else if (predicate.name.equals("younger")) predicate.name = "elder";
  74. else if (predicate.name.equals("husband")) predicate.name = "wife";
  75. else if (predicate.name.equals("wife")) predicate.name = "husband";
  76. else if (predicate.name.equals("child") || predicate.name.equals("son")
  77. || predicate.name.equals("daughter"))
  78. predicate.name = "parent";
  79. else if (predicate.name.equals("parent") || predicate.name.equals("mother")
  80. || predicate.name.equals("father"))
  81. predicate.name = "child";
  82. } // end of method reverseArgs
  83. // The 13 methods which follow are in the FindAll_X family. These participate in a tree-walk which labels every
  84. // node of the family tree with the kinTerm definition which it satisfies (if any).
  85. void fillInNames(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings,
  86. ConstraintObj constraints)
  87. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException,
  88. KSConstraintInconsistency, ClassNotFoundException {
  89. // This method is only called on an ExpandedDef, which is composed of primitive predicates only. remLits
  90. // is an ArrayList<Object> of literals remaining to be popped. All constraints are in constraints. Bindings
  91. // reflects all variables that have been bound to an object so far. The goal here is to get to the END
  92. // of EACH logical chain, find 'Alter' and label that object (person) with KinTerm.
  93. // The current literal is guaranteed to have at least one of its args already bound.
  94. if ((predicate.name.equals("parent")) || (predicate.name.equals("father")) || (predicate.name.equals("mother"))) {
  95. findAllBirthLinks(1, kinTerm, remLits, starStuff, cb, bindings, constraints);
  96. return; }
  97. if ((predicate.name.equals("son")) || (predicate.name.equals("child")) || (predicate.name.equals("daughter"))) {
  98. findAllBirthLinks(0, kinTerm, remLits, starStuff, cb, bindings, constraints);
  99. return; }
  100. if ((predicate.name.equals("spouse")) || (predicate.name.equals("husband")) || (predicate.name.equals("wife"))) {
  101. findAllSpice(kinTerm, remLits, starStuff, cb, bindings, false, constraints);
  102. return; }
  103. if ((predicate.name.equals("divorced")) && (args.size() == 2)) {
  104. findAllSpice(kinTerm, remLits, starStuff, cb, bindings, true, constraints);
  105. return; }
  106. if (predicate.name.substring(0, 1).equals("*")) {
  107. findAllStarLinks(kinTerm, remLits, starStuff, cb, bindings, constraints);
  108. return; }
  109. if ((predicate.name.equals("not")) || (predicate.category instanceof MathCategory)) {
  110. findAllMathLinks(kinTerm, remLits, starStuff, cb, bindings, constraints);
  111. return; }
  112. throw new KSInternalErrorException("Non-primitive predicate found in Literal.fillInNames.");
  113. } // end of method fillInNames
  114. boolean sexMatch(Individual ind, TreeMap bindings, ConstraintObj constraints, Variable argVar, boolean fillInMode) throws KSConstraintInconsistency {
  115. // If Individual has an "Opposite of X" or "Same as X" spec, first we try to resolve that to M or F.
  116. // SexList is the list of gender constraints (after resolution) for ArgVar.
  117. // When in fillInMode, neuter fill_ins are done before gender-specific ones, so we should
  118. // let a neuter individual match an "M" or "F" IFF hasGenderNeutralKinTerm is false and neuter is OK for this arg.
  119. boolean answer = false;
  120. ArrayList<Object> sexList = resolveOppo(bindings, constraints, argVar);
  121. if (ind.gender.equals("?") && (! argVar.neuterOK)) return false;
  122. if ((sexList == null) || ((! sexList.contains("M")) && (! sexList.contains("F")))
  123. || (sexList.contains(ind.gender)))
  124. answer = true;
  125. else if ((fillInMode) && (ind.gender.equals("?"))) {
  126. if ((argVar.neuterOK) && (! ind.hasGenderNeutralKinTerm)
  127. && (argVar.argName.equals("Alter"))) answer = true; }
  128. else if (! ((sexList.contains("M")) || (sexList.contains("F")))) answer = true;
  129. return answer;
  130. } // end of method sexMatch
  131. boolean unEqMatch(Individual ind, ArrayList<Object> unEqList) {
  132. if (unEqList.contains(ind)) return false;
  133. else return true;
  134. } // end of method unEqMatch
  135. void findAllSpice(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings, boolean divReq, ConstraintObj constraints)
  136. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException,
  137. KSConstraintInconsistency, ClassNotFoundException {
  138. // DIVORCE NOTE: divReq is a flag that indicates whether we are handling a marriage-predicate
  139. // [e.g. spouse(X,Y)] when divReq == false, or the divorce predicate [divorced(X,Y)] when
  140. // divReq == true. These are antithetical - to state that
  141. // X & Y are married is to say they are CURRENTLY married, hence not divorced.
  142. // To say X & Y are divorced is to say that they are NO LONGER married.
  143. // The .getDivorceDate() field on a Family record can be null (no information/don't care) or a blank string
  144. // (definitely not divorced) or a non-blank string (definitely divorced).
  145. // One or both args to this literal are already bound. We'll recurse on all spouses of the bound arg.
  146. Variable arg0 = (Variable)args.get(0), arg1 = (Variable)args.get(1); // variable names
  147. Individual alter, ind0 = (Individual)bindings.get(arg0.argName), ind1 = (Individual)bindings.get(arg1.argName), cand, bound1, prospect; // persons
  148. if ((ind0 != null) && (ind1 != null)) { // both bound. Not much to do.
  149. // Validate this spousal link. If not correct for this predicate, FAIL.
  150. if ((! divReq && ! spouseLinkValid(ind0, ind1)) || (divReq && spouseLinkValid(ind0, ind1))) return;
  151. recurse(kinTerm, remLits, starStuff, cb, bindings, constraints);
  152. } // end of both-are-already-bound
  153. Family fam;
  154. String unBoundArg;
  155. Variable unBoundVar;
  156. if (ind0 != null) { // ind0-is-bound
  157. bound1 = ind0;
  158. unBoundVar = arg1;
  159. unBoundArg = arg1.argName;
  160. } // end of ind0-is-bound
  161. else {
  162. bound1 = ind1; // we're guaranteed exactly one of them is bound.
  163. unBoundVar = arg0;
  164. unBoundArg = arg0.argName;
  165. } // end of ind1-is-bound
  166. ArrayList<Object> unEqList = makeUnEqList(unBoundArg, constraints, bindings);
  167. ArrayList<Object> ageSpecList = (ArrayList<Object>)constraints.age.get(unBoundArg);
  168. if (ageSpecList == null) ageSpecList = new ArrayList<Object>();
  169. // Now check all spice
  170. Iterator famIter = bound1.marriages.iterator();
  171. while (famIter.hasNext()) {
  172. fam = (Family)famIter.next();
  173. if (fam.husband == bound1) prospect = fam.wife;
  174. else prospect = fam.husband;
  175. if ( (sexMatch(prospect, bindings, constraints, unBoundVar, true))
  176. && (unEqMatch(prospect, unEqList))
  177. && (meetsDeathSpecStrictly(prospect, (String)constraints.death.get(unBoundArg)))
  178. && (meetsDivSpecStrictly(prospect, (String)constraints.divorce.get(unBoundArg)))
  179. && (meetsStarSpecsStrictly(prospect, unBoundVar, null, bindings, constraints))
  180. && (meetsDivReqStrictly(fam, divReq))
  181. && (meetsAgeSpecStrictly(prospect, ageSpecList, bindings)) ) {
  182. bindings.put(unBoundArg, prospect);
  183. if ((remLits.isEmpty())
  184. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm))) {
  185. alter = (Individual)bindings.get("Alter");
  186. LiteralAbstract1.assignKinTerm(kinTerm, alter, cb, true, null);
  187. } // end of remLits-is-empty-and-negated-constraints-are-strictly-met
  188. else {
  189. TreeMap bindingsCopy = new TreeMap(bindings);
  190. ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
  191. Literal nextLit = null;
  192. while (((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)) && (nextLit == null))
  193. nextLit = cb.pop(remLitsCopy, starStuffCopy, bindingsCopy, kinTerm);
  194. if (nextLit != null)
  195. nextLit.fillInNames(kinTerm, remLitsCopy, starStuff, cb, bindingsCopy, constraints);
  196. else findAllSpice(kinTerm, remLitsCopy, starStuffCopy, cb, bindingsCopy, divReq, constraints);
  197. } // end of else-remLits-not-empty
  198. } // end of prospect-is-a-match
  199. } // end of for-each-marriage
  200. return;
  201. } // end of method findAllSpice
  202. void findAllBirthLinks(int kidArgNmbr, String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings,
  203. ConstraintObj constraints)
  204. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException,
  205. KSConstraintInconsistency, ClassNotFoundException {
  206. Variable kidArg, parArg;
  207. if (kidArgNmbr == 0) {
  208. kidArg = (Variable)args.get(0);
  209. parArg = (Variable)args.get(1);
  210. } // variable names
  211. else {
  212. kidArg = (Variable)args.get(1);
  213. parArg = (Variable)args.get(0);
  214. } // variable names
  215. Family fam;
  216. Individual alter,
  217. kid = (Individual)bindings.get(kidArg.argName),
  218. par = (Individual)bindings.get(parArg.argName); // persons
  219. if ((kid != null) && (par != null)) { // both bound. Not much to do.
  220. // Test these bindings, to validate that par is indeed a parent of kid. If not, FAIL.
  221. if (! par.marriages.contains(kid.birthFamily)) return;
  222. recurse(kinTerm, remLits, starStuff, cb, bindings, constraints);
  223. } // end of both-are-already-bound
  224. else if (par != null) { // parent is bound - we're looking for kids
  225. ArrayList<Object> kidUnEqList = makeUnEqList(kidArg.argName, constraints, bindings);
  226. ArrayList<Object> kidAgeSpecList = (ArrayList<Object>)constraints.age.get(kidArg.argName);
  227. if (kidAgeSpecList == null) kidAgeSpecList = new ArrayList<Object>();
  228. // Armed with constraints, now sift through the kids
  229. Iterator famIter = par.marriages.iterator();
  230. while (famIter.hasNext()) {
  231. fam = (Family)famIter.next();
  232. Iterator kidIter = fam.children.iterator();
  233. while (kidIter.hasNext()) {
  234. kid = (Individual)kidIter.next();
  235. if ( (sexMatch(kid, bindings, constraints, kidArg, true))
  236. && (unEqMatch(kid, kidUnEqList))
  237. && (meetsDeathSpecStrictly(kid, (String)constraints.death.get(kidArg.argName)))
  238. && (meetsDivSpecStrictly(kid, (String)constraints.divorce.get(kidArg.argName)))
  239. && (meetsStarSpecsStrictly(kid, kidArg, null, bindings, constraints))
  240. && (meetsAgeSpecStrictly(kid, kidAgeSpecList, bindings))) {
  241. bindings.put(kidArg.argName, kid);
  242. if ((remLits.isEmpty())
  243. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm))) {
  244. alter = (Individual)bindings.get("Alter");
  245. LiteralAbstract1.assignKinTerm(kinTerm, alter, cb, true, null);
  246. } // end of remLits-is-empty-and-negated-constraints-are-strictly-met
  247. else { // recurse on each kid who qualifies
  248. TreeMap bindingsCopy = new TreeMap(bindings);
  249. ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
  250. Literal nextLit = null;
  251. while (((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)) && (nextLit == null))
  252. nextLit = cb.pop(remLitsCopy, starStuffCopy, bindingsCopy, kinTerm);
  253. if (nextLit != null)
  254. nextLit.fillInNames(kinTerm, remLitsCopy, starStuff, cb, bindingsCopy, constraints);
  255. else fillInNames(kinTerm, remLitsCopy, starStuffCopy, cb, bindingsCopy, constraints);
  256. } // end of remLits-is-not-empty
  257. } // end of found-appropriate-kid
  258. } // end of for-each-kid-in-fam
  259. } // end of for-each-family
  260. return;
  261. } // end of parent-is-bound
  262. else { // kid is bound - seeking the parent(s)
  263. ArrayList<Object> parUnEqList = makeUnEqList(parArg.argName, constraints, bindings);
  264. ArrayList<Object> parAgeSpecList = (ArrayList<Object>)constraints.age.get(parArg.argName);
  265. if (parAgeSpecList == null) parAgeSpecList = new ArrayList<Object>();
  266. // Armed with constraints, now check the parents
  267. if (kid.birthFamily != null) { // if birthfamily exists, it will have a husband and a wife
  268. par = kid.birthFamily.husband; // check the husband
  269. if ( (sexMatch(par, bindings, constraints, parArg, true))
  270. && (unEqMatch(par, parUnEqList))
  271. && (meetsDeathSpecStrictly(par, (String)constraints.death.get(parArg.argName)))
  272. && (meetsDivSpecStrictly(par, (String)constraints.divorce.get(parArg.argName)))
  273. && (meetsStarSpecsStrictly(par, parArg, null, bindings, constraints))
  274. && (meetsAgeSpecStrictly(par, parAgeSpecList, bindings))) { // husband is a match
  275. bindings.put(parArg.argName, par);
  276. if ((remLits.isEmpty())
  277. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm))) {
  278. alter = (Individual)bindings.get("Alter");
  279. LiteralAbstract1.assignKinTerm(kinTerm, alter, cb, true, null);
  280. } // end of remLits-is-empty-and-negated-constraints-are-strictly-met
  281. else { // recurse on husband
  282. TreeMap bindingsCopy = new TreeMap(bindings);
  283. ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
  284. Literal nextLit = null;
  285. while (((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)) && (nextLit == null))
  286. nextLit = cb.pop(remLitsCopy, starStuffCopy, bindingsCopy, kinTerm);
  287. if (nextLit != null)
  288. nextLit.fillInNames(kinTerm, remLitsCopy, starStuffCopy, cb, bindingsCopy, constraints);
  289. else findAllBirthLinks(kidArgNmbr, kinTerm, remLitsCopy, starStuffCopy, cb, bindingsCopy, constraints);
  290. } // end of remLits-is-not-empty
  291. } // end of husband is a match
  292. par = kid.birthFamily.wife; // now check the wife
  293. if ( (sexMatch(par, bindings, constraints, parArg, true))
  294. && (unEqMatch(par, parUnEqList))
  295. && (meetsDeathSpecStrictly(par, (String)constraints.death.get(parArg.argName)))
  296. && (meetsDivSpecStrictly(par, (String)constraints.divorce.get(parArg.argName)))
  297. && (meetsStarSpecsStrictly(par, parArg, null, bindings, constraints))
  298. && (meetsAgeSpecStrictly(par, parAgeSpecList, bindings))) { // wife is a match
  299. bindings.put(parArg.argName, par);
  300. if ((remLits.isEmpty())
  301. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm))) {
  302. alter = (Individual)bindings.get("Alter");
  303. LiteralAbstract1.assignKinTerm(kinTerm, alter, cb, true, null);
  304. } // end of remLits-is-empty-and-negated-constraints-are-strictly-met
  305. else { // recurse on wife -- (use originals, not copies)
  306. ArrayList<Object> starStuffCopy = new ArrayList<Object>(starStuff);
  307. Literal nextLit = null;
  308. while (((remLits.size() > 0) || (starStuffCopy.size() > 0)) && (nextLit == null))
  309. nextLit = cb.pop(remLits, starStuffCopy, bindings, kinTerm);
  310. if (nextLit != null)
  311. nextLit.fillInNames(kinTerm, remLits, starStuffCopy, cb, bindings, constraints);
  312. else findAllBirthLinks(kidArgNmbr, kinTerm, remLits, starStuffCopy, cb, bindings, constraints);
  313. } // end of remLits-is-not-empty
  314. } // end of wife is a match
  315. } // end of birthfamily-exists
  316. return;
  317. } // end of kid-is-bound
  318. } // end of method findAllBirthLinks
  319. boolean spouseLinkValid(Individual ind0, Individual ind1) {
  320. Iterator famIter = ind0.marriages.iterator();
  321. while (famIter.hasNext()) {
  322. Family fam = (Family)famIter.next();
  323. if ((fam.husband == ind1 || fam.wife == ind1) && fam.hasNoDivorceDate())
  324. return true;
  325. } // end of loop thru ind0's families
  326. return false;
  327. } // end of method spouseLinkValid
  328. void findAllStarLinks(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings, ConstraintObj constraints)
  329. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException,
  330. KSConstraintInconsistency, ClassNotFoundException {
  331. // The current literal is a User Defined Property (UDP) like "bald(X, GM)." If the variable GM is unbound, we will find ALL
  332. // the persons who (1) have baldness = X, and (2) meet all other constraints on the variable GM. For each one, we recurse on
  333. // remLits (the Remaining Literals) until we've found Alter and labeled that person with kinTerm.
  334. // If X (the value of the UDP) is blank but GM's *bald UDP already has a value, we'll adopt that value for X and recurse.
  335. // If X is bound to an empty list, and GM is unbound, we'll bind GM successively to each person whose baldness meets the
  336. // constraints on X, and who otherwise meets the constraints on GM.
  337. // One or both args to this literal are already bound.
  338. Variable personVar = (Variable)args.get(1);
  339. Individual person = (Individual)bindings.get(personVar.argName); // null = that variable not yet bound
  340. Argument arg0 = (Argument)args.get(0);
  341. if (arg0 instanceof Constant) bindings.put(arg0.argName, arg0.bindingVal()); // if this is a fresh constant, bind it.
  342. // Check to see if both arguments are bound already. If so, just recurse. There's no need to validate that this
  343. // literal is true, because a star-literal is also a constraint; it was validated when the args were bound.
  344. if ((person != null) && (bindings.get(arg0.argName) != null))
  345. recurse(kinTerm, remLits, starStuff, cb, bindings, constraints);
  346. // If we're here, only one arg is bound. Recurse on all legal bindings of the unbound arg.
  347. else if (person != null) { // arg0 is unbound
  348. UserDefinedProperty udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
  349. if (udp.value.size() > 0) { // person-has-a-value-for-this-UDP
  350. // if arg0 has a different value, FAIL
  351. if ((arg0.getVal().size() > 0) && (! listEqual(arg0.getVal(), udp.value))) return;
  352. // unbound Variable, Constant or MathVariable has no value, so proceed to bind & recurse
  353. if (arg0 instanceof MathVariable) ((MathVariable)arg0).link(udp);
  354. else arg0.addVal(udp.value);
  355. bindings.put(arg0.argName, arg0.bindingVal()); // tail recursion - we can use original copy of bindings
  356. recurse(kinTerm, remLits, starStuff, cb, bindings, constraints);
  357. } // end of person-had-a-value-for-this-UDP
  358. else return; // person has no value & arg0 has no value. FAIL.
  359. } // end of person-was-bound
  360. else { // person-is-unbound. So recurse on each person in population that has the prescribed value
  361. // NOTE: It is possible to reach this point with person unbound and arg0 bound to an empty list = arg0.value
  362. // In that case, there is no prescribed value EXCEPT for the constraints on the value of the MathVarible arg0
  363. ArrayList<Individual> census = Context.current.individualCensus;
  364. ArrayList<Object> requiredVal = arg0.getVal(), starBindings = new ArrayList<Object>(); // starBindings is a throwaway list
  365. Individual guy, valPerson = null;
  366. UserDefinedProperty udp;
  367. TreeMap bindingsCopy = new TreeMap(bindings); // for multiple recursive descents
  368. boolean winner = false;
  369. for (int i=0; i < census.size(); i++) {
  370. guy = (Individual)census.get(i);
  371. udp = (UserDefinedProperty)guy.userDefinedProperties.get(predicate.name);
  372. if ((i == 0) && (arg0.argType.equals("Variable")) && (! udp.typ.equals("individual")))
  373. throw new KSInternalErrorException("In FindAllStarLinks: Variable set equal to UDP of type '" + udp.typ
  374. + "' in\n" + cb); // only need to check once
  375. if ((requiredVal.size() > 0) && listEqual(requiredVal, udp.value) &&
  376. guy.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)) // arg0 NOT empty, & a match
  377. winner = true;
  378. else if ((requiredVal.isEmpty()) && (arg0 instanceof MathVariable) && // arg0 empty
  379. valListCheck(arg0, udp, guy, bindings, constraints, starBindings) && // UDP val meets arg0 constraints
  380. guy.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)) // other constraints met
  381. winner = true;
  382. else if (arg0.argType.equals("Variable")) {
  383. // arg0 is bound to SOMETHING - an empty list or a person
  384. Object mysteryObj = bindings.get(arg0.argName);
  385. if (mysteryObj instanceof Individual) valPerson = (Individual)mysteryObj;
  386. if ((valPerson != null) && (udp.value.size() == 1) && udp.value.contains(valPerson)
  387. && guy.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings))
  388. winner = true; // arg0 is already bound to a person, who matches UDP's value
  389. else if ((valPerson == null) && (udp.value.size() == 1)
  390. && valPersonCheck(arg0, udp, bindings, constraints, starBindings, cb)
  391. && guy.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)) {
  392. bindingsCopy.put(arg0.argName, udp.value.get(0));
  393. winner = true; // bind arg0 to the person in the UDP's value, but only on the COPY of bindings
  394. }
  395. } // end of arg0-is-a-Variable
  396. if (winner) {
  397. winner = false;
  398. bindingsCopy.put(personVar.argName, guy);
  399. recurse(kinTerm, remLits, starStuff, cb, bindingsCopy, constraints);
  400. } // end of found-a-winner
  401. } // end of loop thru all people in this context
  402. } // end of person-was-unbound
  403. return;
  404. } // end of method findAllStarLinks
  405. boolean valListCheck(Argument arg0, UserDefinedProperty udp, Individual guy, TreeMap bindings,
  406. ConstraintObj constraints, ArrayList<Object> starBindings)
  407. throws KSInternalErrorException, KSConstraintInconsistency {
  408. // arg0 has no value, but may have constraints. If udp has no value, we FAIL
  409. // If udp has a value which satisfies the constraints on arg0 (if any), we succeed.
  410. // If udp's value violates a constraint, we FAIL.
  411. if (udp.value.isEmpty()) return false;
  412. for (int i=0; i < udp.value.size(); i++) {
  413. Class clazz;
  414. try {clazz = guy.getUDPClass(udp.typ);
  415. if (! guy.checkProposedVal(clazz, udp.value.get(i), arg0, bindings, starBindings, constraints))
  416. return false;
  417. }catch(Exception exc){
  418. throw new KSInternalErrorException("In FindAllStarLinks: Class Cast Exception via getUDPClass"); }
  419. } // end of loop thru values of UDP
  420. return true;
  421. } // end of method valListCheck
  422. boolean valPersonCheck(Argument arg0, UserDefinedProperty udp, TreeMap bindings, ConstraintObj constraints,
  423. ArrayList<Object> starBindings, ClauseBody cb) throws KSInternalErrorException, KSConstraintInconsistency {
  424. // udp has a single value, which should be a person (exception if not). We are considering binding arg0
  425. // to that person. So if that person fails to satisfy any constraint on arg0, we fail. Else succeed.
  426. Individual pers;
  427. try { pers = (Individual)udp.value.get(0);
  428. return pers.meetsConstraintsStrictly((Variable)arg0, constraints, bindings, starBindings);
  429. }catch(Exception exc) {
  430. throw new KSInternalErrorException("In FindAllStarLinks, Variable '" + arg0.argName + "' = non-Person in\n" + cb);}
  431. } // end of method valPersonCheck
  432. void findAllMathLinks(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings, ConstraintObj constraints)
  433. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException,
  434. KSConstraintInconsistency, ClassNotFoundException {
  435. // The current literal is a math predicate (e.g. lessThan(X,Y) ) or the primitive predicate 'not(equal(X,Y)).'
  436. // If both args are bound, we verify that the required relationship holds and go on.
  437. // If only xArg is bound, it must be that yArg appears in another literal not yet processed; that literal must be
  438. // either a *-predicate (meaning yArg represents some person Z's value for that UDP) or a math predicate imposing an additional
  439. // constraint on yArg.
  440. // If there were any birth- or spousal-link to define Z, Z would be bound & Alter found before now. So it must be that both yArg
  441. // and Z are unbound. The only way we'll "FindAll" legal Z's is to bind Y to something (e.g. an empty list) and recurse. This
  442. // will allow processing of the next *-pred (in FindAllStarLinks) and get Y bound.
  443. Argument xVar, yVar;
  444. MathOperator mathOp = null;
  445. if (predicate.category instanceof MathCategory) { // this is a math predicate
  446. xVar = (Argument)args.get(0);
  447. yVar = (Argument)args.get(1);
  448. if (predicate.name.equals("contains")) mathOp = new Contains();
  449. else if (predicate.name.equals("lessThan")) mathOp = new LessThan();
  450. else if (predicate.name.equals("lessOrEql")) mathOp = new LessOrEql();
  451. else if (predicate.name.equals("greaterThan")) mathOp = new GreaterThan();
  452. else if (predicate.name.equals("greaterOrEql")) mathOp = new GreaterOrEql();
  453. } // end of math-predicate
  454. else { // must be not-equal
  455. Literal subLit = (Literal)args.get(0);
  456. xVar = (Argument)subLit.args.get(0);
  457. yVar = (Argument)subLit.args.get(1);
  458. mathOp = new NotEqual();
  459. } // end of not-equal
  460. ArrayList<Object> xValue = (ArrayList<Object>)bindings.get(xVar.argName), yValue = (ArrayList<Object>)bindings.get(yVar.argName);
  461. if ((xValue != null) && (yValue != null)) {
  462. if (! mathOp.compare(xVar.getVal(), yVar.getVal())) return; // if invalid - FAIL
  463. // Done. Both bound and values validated.
  464. } else { // must be only-1-is-bound
  465. if ((xValue != null) && (yValue == null)) // X is already bound; bind Y
  466. bindings.put(yVar.argName, yVar.bindingVal());
  467. else // Y is bound; bind X
  468. bindings.put(xVar.argName, xVar.bindingVal());
  469. } // end of only-1-is-bound
  470. recurse(kinTerm, remLits, starStuff, cb, bindings, constraints); // tail recursion; use originals
  471. } // end of method findAllMathLinks
  472. void recurse(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings, ConstraintObj constraints)
  473. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException, KSConstraintInconsistency {
  474. Literal nextLit = null;
  475. ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
  476. try {
  477. while (((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)) && (nextLit == null))
  478. nextLit = cb.pop(remLitsCopy, starStuffCopy, bindings, kinTerm);
  479. if (nextLit != null) {
  480. nextLit.fillInNames(kinTerm, remLitsCopy, starStuffCopy, cb, bindings, constraints);
  481. return;
  482. } else { // bingo!
  483. if (negatedConstraintsStrictlySatisfied(starStuffCopy, bindings, constraints, kinTerm)) {
  484. Individual alter = (Individual)bindings.get("Alter");
  485. if (alter == null)
  486. throw new KSNoChainOfRelations2Alter("in fillInNames: End of logical chain reached without finding 'Alter' in definition of " + kinTerm);
  487. else LiteralAbstract1.assignKinTerm(kinTerm, alter, cb, true, null);
  488. } // end of remLitsCopy-is-empty-and-negated-constraints-are-strictly-met
  489. return;
  490. } // end of bingo!
  491. }catch(ClassNotFoundException exc) {
  492. throw new KSInternalErrorException("In FindAllStarLinks: ClassNotFound Exception via negatedConstraintsStrictlySatisfied");}
  493. } // end of method recurse
  494. boolean negatedConstraintsStrictlySatisfied(ArrayList<Object> starStuff, TreeMap bindings, ConstraintObj constraints, String kinTerm)
  495. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException, ClassNotFoundException {
  496. // This method mirrors negatedConstraintsSatisfied above, except that it uses fillInNames_bool to test
  497. // for satisfiability; fillInNames_bool, in turn, requires strict satisfaction of all constraints.
  498. // Check to see if any of the ClauseBodies in the Negated constraint are true. If any one
  499. // of them is true, the test is failed and we return false.
  500. if ((constraints.negated == null) || (constraints.negated.isEmpty())) return true;
  501. Individual ego = (Individual)bindings.get("Ego");
  502. ClauseBody cb;
  503. ArrayList<Object> bodyCopy;
  504. TreeMap bindingsCopy = new TreeMap(bindings);
  505. ConstraintObj constraintsCopy;
  506. for (int i=0; i < constraints.negated.size(); i++) {
  507. cb = (ClauseBody)constraints.negated.get(i);
  508. constraintsCopy = new ConstraintObj(constraints);
  509. constraintsCopy.negated = new ArrayList<Object>(); // to prevent infinite recursion
  510. // Any restrictions on variables induced by a negated clause should apply only to a
  511. // "deep copy" of the args found in the main clausebody, not the main args themselves.
  512. bodyCopy = new ArrayList<Object>();
  513. for (int k=0; k < cb.body.size(); k++)
  514. bodyCopy.add(((Literal)cb.body.get(k)).copy());
  515. // Keep all current constraints except cb, and add any new ones appearing in cb.
  516. try {
  517. for (int j=0; j < bodyCopy.size(); j++)
  518. if (! (((Literal)bodyCopy.get(j)).constraintCheck(ego.gender, constraintsCopy, new ArrayList<Object>(), starStuff)))
  519. throw new KSConstraintInconsistency(" ");
  520. if (! LiteralAbstract1.finalConstraintCheck(ego.gender, bindingsCopy, constraintsCopy, bodyCopy, new ArrayList<Object>(), starStuff))
  521. throw new KSConstraintInconsistency(" ");
  522. // finalConstraintCheck does post-processing & a final conflict-check.
  523. Literal next = null;
  524. while (((bodyCopy.size() > 0) || (starStuff.size() > 0)) && (next == null))
  525. next = cb.pop(bodyCopy, starStuff, bindingsCopy, kinTerm); // next = first non-constraint literal in body
  526. if (next == null)
  527. throw new KSBadHornClauseException("No processable literals in negated clause:\n not("
  528. + cb.body + ")");
  529. if (next.fillInNames_bool(kinTerm, bodyCopy, starStuff, cb, bindingsCopy, constraintsCopy, null, new ArrayList<Object>()))
  530. return false;
  531. } catch (KSConstraintInconsistency e) { }
  532. catch (KSNoChainOfRelations2Alter e) { }
  533. // If a ConstraintInconsistency or NoChainOfRelationsToAlter occurs here, it means the
  534. // constraints alone are enough to make this clauseBody impossible.
  535. // So treat this the same as a failure by fillInNames_bool; go on to the next clauseBody (if any).
  536. } // end of for-i=each-negated-constraint
  537. return true;
  538. } // end of method negatedConstraintsStrictlySatisfied
  539. boolean fillInNames_bool(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings,
  540. ConstraintObj constraints, Individual goalPerson, ArrayList<Object> path)
  541. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException,
  542. KSConstraintInconsistency, ClassNotFoundException {
  543. // This method mimics fillInNames above. The difference is that this method does not label Alter
  544. // if it successfully gets to the end of a logical chain of bindings - it merely returns 'true'
  545. // to indicate that it COULD have. This information is used by negatedConstraintsStrictlySatisfied
  546. // to determine whether a negated constraint could be satisfied by objects already created.
  547. if ((predicate.name.equals("parent")) || (predicate.name.equals("father"))
  548. || (predicate.name.equals("mother")))
  549. return findAllBirthLinks_bool(1, kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path);
  550. if ((predicate.name.equals("son")) || (predicate.name.equals("child"))
  551. || (predicate.name.equals("daughter")))
  552. return findAllBirthLinks_bool(0, kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path);
  553. if ((predicate.name.equals("spouse")) || (predicate.name.equals("husband"))
  554. || (predicate.name.equals("wife")))
  555. return findAllSpice_bool(kinTerm, remLits, starStuff, cb, bindings, false, constraints, goalPerson, path);
  556. if ((predicate.name.equals("divorced")) && (args.size() == 2))
  557. return findAllSpice_bool(kinTerm, remLits, starStuff, cb, bindings, true, constraints, goalPerson, path);
  558. if (predicate.name.substring(0, 1).equals("*"))
  559. return findAllStarLinks_bool(kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path);
  560. if ((predicate.name.equals("not")) || (predicate.category instanceof MathCategory))
  561. return findAllMathLinks_bool(kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path);
  562. throw new KSInternalErrorException("Non-primitive predicate found in Literal.fillInNames_bool.");
  563. } // end of method fillInNames_bool
  564. boolean findAllSpice_bool(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb, TreeMap bindings, boolean divReq,
  565. ConstraintObj constraints, Individual goalPerson, ArrayList<Object> path)
  566. throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
  567. // DIVORCE NOTE: divReq is a flag that indicates whether we are handling a marriage-predicate
  568. // [e.g. spouse(X,Y)] when divReq == false, or the divorce predicate [divorced(X,Y)] when
  569. // divReq == true. These are antithetical - to state that
  570. // X & Y are married is to say they are CURRENTLY married, hence not divorced.
  571. // To say X & Y are divorced is to say that they are NO LONGER married.
  572. // The .getDivorceDate() field on a Family record can be null (no information/don't care) or a blank string
  573. // (definitely not divorced) or a non-blank string (definitely divorced).
  574. // This method mimics findAllSpice, but returns 'true' instead of naming anyone.
  575. Variable arg0 = (Variable)args.get(0), arg1 = (Variable)args.get(1); // variable names
  576. Individual alter, ind0 = (Individual)bindings.get(arg0.argName), ind1 = (Individual)bindings.get(arg1.argName), cand, bound1, prospect; // persons
  577. alter = (Individual)bindings.get("Alter");
  578. if ((remLits.isEmpty()) && (alter != null) && (ind0 != null) && (ind1 != null)) {
  579. // Validate the spousal link. If not correct for this predicate, FAIL
  580. if (((! divReq) && (! spouseLinkValid(ind0, ind1))) || (divReq && spouseLinkValid(ind0, ind1)))
  581. return false;
  582. if ((goalPerson == null) && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  583. return true;
  584. else if ((goalPerson != null) && (goalPerson == (Individual)bindings.get("Alter"))
  585. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  586. return true;
  587. else return false;
  588. }
  589. if ((ind0 != null) && (ind1 != null)) { // both bound. Not much to do.
  590. // Validate the spousal link. If not married, FAIL
  591. if (((! divReq) && (! spouseLinkValid(ind0, ind1))) || (divReq && spouseLinkValid(ind0, ind1)))
  592. return false;
  593. return recurse_bool(kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path, alter);
  594. } // end of both-are-already-bound
  595. Family fam;
  596. String unBoundArg;
  597. Variable unBoundVar;
  598. if (ind0 != null) { // ind0-is-bound
  599. bound1 = ind0;
  600. unBoundVar = arg1;
  601. unBoundArg = arg1.argName;
  602. } // end of ind0-is-bound
  603. else {
  604. bound1 = ind1; // we're guaranteed exactly one of them is bound.
  605. unBoundVar = arg0;
  606. unBoundArg = arg0.argName;
  607. } // end of ind1-is-bound
  608. ArrayList<Object> unEqList = makeUnEqList(unBoundArg, constraints, bindings);
  609. if (unEqList == null) unEqList = new ArrayList<Object>();
  610. ArrayList<Object> ageSpecList = (ArrayList<Object>)constraints.age.get(unBoundArg);
  611. if (ageSpecList == null) ageSpecList = new ArrayList<Object>();
  612. // Now check all spice. We're looking for the first success. Fail only if no successes found.
  613. Iterator famIter = bound1.marriages.iterator();
  614. while (famIter.hasNext()) {
  615. fam = (Family)famIter.next();
  616. if (fam.husband == bound1) prospect = fam.wife;
  617. else prospect = fam.husband;
  618. if ( (sexMatch(prospect, bindings, constraints, unBoundVar, true))
  619. && (unEqMatch(prospect, unEqList))
  620. && (meetsDeathSpecStrictly(prospect, (String)constraints.death.get(unBoundArg)))
  621. && (meetsDivSpecStrictly(prospect, (String)constraints.divorce.get(unBoundArg)))
  622. && (meetsStarSpecsStrictly(prospect, unBoundVar, null, bindings, constraints))
  623. && (meetsDivReqStrictly(fam, divReq))
  624. && (meetsAgeSpecStrictly(prospect, ageSpecList, bindings)) ) {
  625. bindings.put(unBoundArg, prospect);
  626. if (remLits.isEmpty()) {
  627. if (((goalPerson == null) && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  628. || ((goalPerson != null) && (goalPerson == (Individual)bindings.get("Alter"))
  629. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))) {
  630. path.add("S");
  631. return true;
  632. } // end of remLits-is-empty-and-negated-constraints-are-strictly-met
  633. } // end of remLits-is-empty
  634. else {
  635. ArrayList<Object> pathCopy = new ArrayList<Object>(path), remLitsCopy = new ArrayList<Object>(remLits);
  636. ArrayList<Object> starStuffCopy = new ArrayList<Object>(starStuff);
  637. pathCopy.add("S");
  638. TreeMap bindingsCopy = new TreeMap(bindings);
  639. Literal nextLit = null;
  640. while (((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)) && (nextLit == null))
  641. nextLit = cb.pop(remLitsCopy, starStuffCopy, bindingsCopy, kinTerm);
  642. if (nextLit != null) {
  643. if (nextLit.fillInNames_bool(kinTerm, remLitsCopy, starStuffCopy, cb, bindingsCopy, constraints, goalPerson, pathCopy)) {
  644. updatePath(path, pathCopy);
  645. return true;
  646. } // end of nextLit.fillInNames_bool-succeeded
  647. } // end of nextLit != null
  648. else {
  649. if (findAllSpice_bool(kinTerm, remLitsCopy, starStuffCopy, cb, bindingsCopy, divReq, constraints, goalPerson, pathCopy)) {
  650. updatePath(path, pathCopy);
  651. return true;
  652. } // end of this.findAllSpice_bool-succeeded
  653. } // end of nextLit-does-equal-null
  654. } // end of else-remLits-not-empty
  655. } // end of prospect-is-a-match
  656. } // end of for-each-marriage
  657. return false;
  658. } // end of method findAllSpice_bool
  659. boolean recurse_bool(String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb,
  660. TreeMap bindings, ConstraintObj constraints, Individual goalPerson, ArrayList<Object> path, Individual alter)
  661. throws KSBadHornClauseException, KSNoChainOfRelations2Alter, KSInternalErrorException, KSConstraintInconsistency {
  662. Literal nextLit = null;
  663. while (((remLits.size() > 0) || (starStuff.size() > 0)) && (nextLit == null))
  664. nextLit = cb.pop(remLits, starStuff, bindings, kinTerm);
  665. try {
  666. if (nextLit != null)
  667. return nextLit.fillInNames_bool(kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path);
  668. else {
  669. if ((remLits.isEmpty()) && (alter != null)) {
  670. if ((goalPerson == null) && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  671. return true;
  672. else if ((goalPerson != null) && (goalPerson == alter)
  673. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  674. return true;
  675. else return false;
  676. }else throw new KSNoChainOfRelations2Alter("In fillInNames_bool: End of logical chain reached without finding 'Alter' in definition of " + kinTerm);
  677. } // end of nextLit-is-null
  678. }catch(ClassNotFoundException cnf) { throw new KSInternalErrorException("In fillInNames_bool: ClassNotFound Exception"); }
  679. } // end of method recurse_bool
  680. public void updatePath(ArrayList<Object> path, ArrayList<Object> pathCopy) {
  681. for (int i = path.size(); i < pathCopy.size(); i++)
  682. path.add(pathCopy.get(i));
  683. } // end of method updatePath
  684. boolean findAllBirthLinks_bool(int kidArgNmbr, String kinTerm, ArrayList<Object> remLits, ArrayList<Object> starStuff, ClauseBody cb,
  685. TreeMap bindings, ConstraintObj constraints, Individual goalPerson, ArrayList<Object> path)
  686. throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
  687. // Mimics findAllBirthLinks above, but returns true instead of naming anyone.
  688. Variable kidArg, parArg;
  689. if (kidArgNmbr == 0) {
  690. kidArg = (Variable)args.get(0);
  691. parArg = (Variable)args.get(1);
  692. } // variable names
  693. else {
  694. kidArg = (Variable)args.get(1);
  695. parArg = (Variable)args.get(0);
  696. } // variable names
  697. Individual alter, kid = (Individual)bindings.get(kidArg.argName), par = (Individual)bindings.get(parArg.argName); // persons
  698. alter = (Individual)bindings.get("Alter");
  699. if ((remLits.isEmpty()) && (alter != null) && (kid != null) && (par != null)) {
  700. // Test these bindings, to validate that par is indeed a parent of kid. If not, FAIL.
  701. if (! par.marriages.contains(kid.birthFamily)) return false;
  702. if ((goalPerson == null) && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  703. return true;
  704. else if ((goalPerson != null) && (goalPerson == (Individual)bindings.get("Alter"))
  705. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  706. return true;
  707. else return false;
  708. } // end of all-bound-and-no-remlits-left
  709. if ((kid != null) && (par != null)) { // both bound. Not much to do.
  710. // Test these bindings, to validate that par is indeed a parent of kid. If not, FAIL.
  711. if (! par.marriages.contains(kid.birthFamily)) return false;
  712. Literal nextLit = null;
  713. while (((remLits.size() > 0) || (starStuff.size() > 0)) && (nextLit == null))
  714. nextLit = cb.pop(remLits, starStuff, bindings, kinTerm);
  715. if (nextLit != null)
  716. return nextLit.fillInNames_bool(kinTerm, remLits, starStuff, cb, bindings, constraints, goalPerson, path);
  717. else {
  718. if ((remLits.isEmpty()) && (alter != null)) {
  719. if ((goalPerson == null) && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  720. return true;
  721. else if ((goalPerson != null) && (goalPerson == (Individual)bindings.get("Alter"))
  722. && (negatedConstraintsStrictlySatisfied(starStuff, bindings, constraints, kinTerm)))
  723. return true;
  724. else return false;
  725. }else throw new KSNoChainOfRelations2Alter("in fillInNames: End of logical chain reached without finding 'Alter' in definition of " + kinTerm);
  726. } // end of nextLit-is-null
  727. } // end of both-are-already-bound
  728. Family fam;
  729. if (par != null) { // parent is bound - we're looking for kids
  730. ArrayList<Object> kidUnEqList = makeUnEqList(kidArg.argName, constraints, bindings);
  731. ArrayList<Object> kidAgeSpecList = (ArrayList<Object>)constraints.age.get(kidArg.argName);
  732. if (kidAgeSpecList == null) kidAgeSpecList = new ArrayList<Object>();
  733. // Armed with constraints, now sift through the kids
  734. It

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