PageRenderTime 36ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/code/LiteralAbstract2.java

http://silkin.googlecode.com/
Java | 1034 lines | 790 code | 64 blank | 180 comment | 506 complexity | 7a6e6bcda563990c586cdac9e51665ea 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 continues 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: LiteralAbstract2, this one,
  8. and Literal.
  9. @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
  10. */
  11. public abstract class LiteralAbstract2 extends LiteralAbstract1 {
  12. public static final String stdLitType = "Literal";
  13. /** Generic zero-arg constructor. Primarily for use in Serialization */
  14. public LiteralAbstract2() {
  15. super();
  16. argType = stdLitType;
  17. }
  18. /** Produce the set-difference of list1 minus list2; remove each item in list2 from list1 -- if it's there.
  19. @param list1 the base list, from which we will subtract.
  20. @param list2 the list of items to be subtracted.
  21. @return the set difference.
  22. */
  23. public static ArrayList<Object> setDifference(ArrayList<Object> list1, ArrayList<Object> list2) {
  24. if ((list2 == null) || (list2.isEmpty())) return list1;
  25. ArrayList<Object> result = new ArrayList<Object>();
  26. Object obj;
  27. for (int i=0; i < list1.size(); i++) {
  28. obj = list1.get(i);
  29. if (! list2.contains(obj)) result.add(obj);
  30. }
  31. return result;
  32. } // end of method setDifference
  33. // The following 21 methods are all related to generating example-persons who illustrate the kinship
  34. // definition contained in the enclosing clauseBody. They all FindOrCreate_X, i.e. they find a single
  35. // existing person to use, or create one if no suitable person can be re-used.
  36. // This is in contrast to the set of methods which follows, the FindAll_X methods, which only label existing persons.
  37. boolean findOrCreate(ArrayList<Object> cbody, ArrayList<Object> starStuff, TreeMap bindings, TreeMap badBindings, ArrayList<Object> starBindings,
  38. ConstraintObj constraints, String kinTerm, ClauseBody cb, ArrayList<Object> pcStr, Dyad dyad)
  39. throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
  40. int kidFlag = 0, parFlag = 0, mateFlag = 0; // signals re: past failures
  41. // Find the correct method for this Primitive Predicate & call it.
  42. // if (Context.breakFlag) Context.breakpoint();
  43. if (predicate.name.equals("parent"))
  44. return findOrCreateBirthLink("?", "?", 0, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
  45. if (predicate.name.equals("child"))
  46. return findOrCreateBirthLink("?", "?", 1, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
  47. if (predicate.name.equals("father"))
  48. return findOrCreateBirthLink("M", "?", 0, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
  49. if (predicate.name.equals("mother"))
  50. return findOrCreateBirthLink("F", "?", 0, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
  51. if (predicate.name.equals("son"))
  52. return findOrCreateBirthLink("?", "M", 1, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
  53. if (predicate.name.equals("daughter"))
  54. return findOrCreateBirthLink("?", "F", 1, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
  55. if ((predicate.name.equals("husband")) || (predicate.name.equals("wife"))
  56. || (predicate.name.equals("spouse")))
  57. return findOrCreateSpouse(cbody, starStuff, bindings, badBindings, starBindings, false, constraints, mateFlag, false, kinTerm, cb, pcStr, dyad);
  58. if ((predicate.name.equals("divorced")) && (args.size() == 2))
  59. return findOrCreateSpouse(cbody, starStuff, bindings, badBindings, starBindings, true, constraints, mateFlag, false, kinTerm, cb, pcStr, dyad);
  60. if (predicate.name.substring(0, 1).equals("*"))
  61. return findOrCreateStarLink(cbody, starStuff, bindings, badBindings, starBindings, constraints, 0, false, kinTerm, cb, pcStr, dyad);
  62. if ((predicate.name.equals("not")) || (predicate.category instanceof MathCategory))
  63. return findOrCreateMathLink(cbody, starStuff, bindings, badBindings, starBindings, constraints, false, kinTerm, cb, pcStr, dyad);
  64. throw new KSInternalErrorException("Non-Primitive Predicate Encountered in Literal.findOrCreate.\nLiteral is: " + this);
  65. } // end of dispatch method findOrCreate
  66. boolean findOrCreateBirthLink(String parSex, String kidSex, int parArg, ArrayList<Object> remLits, ArrayList<Object> starStuff, TreeMap bindings,
  67. TreeMap badBindings, ArrayList<Object> starBindings, ConstraintObj constraints, int kidFlag, int parFlag,
  68. boolean keepBB, String kinTerm, ClauseBody cb, ArrayList<Object> pcStr, Dyad dyad)
  69. throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
  70. // This handles parent, father, mother, son, & daughter predicates via the 1st 3 parameters.
  71. // For each arg, either (1) a suitable Individual already exists in the Indiv-Census
  72. // so we find it and bind it, then recurse on remLits. OR
  73. // (2) we create a suitable Individual and add it to the bindings - honoring constraints - then recurse.
  74. // badBindings is a TreeMap of variables (argNames) & lists of prohibited bindings (individuals)
  75. int kidArg, resetInd = Context.current.indSerNumGen, resetFam = Context.current.famSerNumGen;
  76. int sbSize = starBindings.size();
  77. kidArg = (parArg + 1) % 2;
  78. Variable parent = (Variable)args.get(parArg), child = (Variable)args.get(kidArg);
  79. Individual parentIndiv = (Individual)bindings.get(parent.argName), childIndiv = (Individual)bindings.get(child.argName);
  80. String bindingMade = null, parentSex = parSex;
  81. // if (Context.breakFlag) System.out.println("F/C_BirthLink on " + this);
  82. Argument argBound = null;
  83. ArrayList<Object> parentSexList;
  84. if (parSex.equals("?")) {
  85. parentSexList = resolveOppo(bindings, constraints, parent);
  86. if (parentSexList == null) parentSex = "?";
  87. else if (parentSexList.contains("F")) parentSex = "F";
  88. else if (parentSexList.contains("M")) parentSex = "M";
  89. }
  90. Family fam = null;
  91. if (LiteralAbstract1.negativeConstraintPhase) {
  92. // One or both of these may have been bound earlier in a 'positive' phase, and carried (via bindings
  93. // list) into a 'negatedConstraintsSatisfied' phase. So double check constraints. Use the _Strictly_
  94. // versions,'cuz we don't want to change anything on a bound arg/object pair.
  95. if ((childIndiv != null) && (! childIndiv.meetsConstraintsStrictly(child, constraints, bindings, starBindings)))
  96. return false;
  97. if ((parentIndiv != null) && (! parentIndiv.meetsConstraintsStrictly(parent, constraints, bindings, starBindings)))
  98. return false;
  99. } // end of if-negativeConstraintPhase
  100. // we know that either parent or child (maybe both) already exists
  101. if ((parentIndiv != null) && (childIndiv == null)) { // parent already exists; look for child of right sex
  102. Individual existingKid;
  103. ArrayList<Object> badKids = (ArrayList<Object>)badBindings.get(child.argName); // list of individuals we can NOT accept
  104. if (badKids == null) badKids = new ArrayList<Object>();
  105. existingKid = kidSearch(parentIndiv, kidSex, child, constraints, bindings, badKids, starBindings, cb);
  106. if (existingKid == null) { // no match found among existing kids
  107. ArrayList<Object> kidSexList;
  108. if (kidSex.equals("?")) {
  109. kidSexList = resolveOppo(bindings, constraints, child);
  110. if (kidSexList == null) kidSex = "?";
  111. else if (kidSexList.contains("F")) kidSex = "F";
  112. else if (kidSexList.contains("M")) kidSex = "M";
  113. }
  114. // kidFlag = 0 means we've never created a kid for this variable
  115. // kidFlag = 1-2 means we created a kid in family#0 previously (M & F) & it didn't work
  116. // kidFlag = 3-4 means we've used or created a 2nd marriage & new kid - still didn't work
  117. // kidFlag = 5-6 means we've created a new marriage & new kid - nothing works
  118. if (kidFlag == 0) fam = findOrMakeMarriage(parentIndiv, 0, parent.argName, constraints);
  119. else if (kidFlag <= 2) // try 2nd marriage
  120. fam = findOrMakeMarriage(parentIndiv, 1, parent.argName, constraints);
  121. else if (kidFlag <= 4) // force a new marriage
  122. fam = findOrMakeMarriage(parentIndiv, 99, parent.argName, constraints);
  123. else if (kidFlag >= 5) return false; // nothing left to try
  124. kidFlag++;
  125. BoolFlag failFlag = new BoolFlag(false);
  126. childIndiv = new Individual("*&^%$", kidSex, fam, null, child.argName, null, bindings,
  127. starBindings, constraints, child, failFlag, cb);
  128. if (failFlag.value) {
  129. LiteralAbstract1.failReason = failFlag.reason;
  130. return false;
  131. } // end of failFlag===true
  132. if ((fam != null) && (fam.getMarriageDate().length() < 4)) fam.generateMarriageDate();
  133. } // end of if-no-suitable-existingKid-found
  134. else childIndiv = existingKid;
  135. bindings.put(child.argName, childIndiv);
  136. if (childIndiv.node == null) childIndiv.node = new Node();
  137. else childIndiv.node.appearances++;
  138. bindingMade = child.argName;
  139. if (dyad != null) dyad.path.add(childIndiv);
  140. argBound = child;
  141. cb.pcCounter++;
  142. addToPCString(pcStr, parentIndiv, childIndiv, false);
  143. child.treeLevel = parent.treeLevel - 1;
  144. if (bindingMade.equals("Alter")) {
  145. cb.level = child.treeLevel;
  146. if (dyad != null) dyad.alter = childIndiv;
  147. }
  148. } // end of if-parent-already-exists
  149. else if ((parentIndiv == null) && (childIndiv != null)) { // kid already exists, parent doesn't
  150. BoolFlag failFlag = new BoolFlag(false);
  151. fam = findOrMakeBirthFamily(childIndiv, parentSex, parent.argName, null, bindings,
  152. starBindings, constraints, parent, failFlag, cb);
  153. if (failFlag.value) {
  154. LiteralAbstract1.failReason = failFlag.reason;
  155. return false;
  156. } // end of failFlag===true
  157. ArrayList<Object> badParents = (ArrayList<Object>)badBindings.get(parent.argName);
  158. if (badParents == null) badParents = new ArrayList<Object>();
  159. parentIndiv = parentSearch(fam, parentSex, parent, constraints, bindings, badParents, parFlag, starBindings, cb);
  160. if (parentIndiv == null) return false;
  161. if ((fam != null) && (fam.getMarriageDate().length() < 4)) fam.generateMarriageDate();
  162. bindings.put(parent.argName, parentIndiv);
  163. if (parentIndiv.node == null) parentIndiv.node = new Node();
  164. else parentIndiv.node.appearances++;
  165. bindingMade = parent.argName;
  166. if (dyad != null) dyad.path.add(parentIndiv);
  167. argBound = parent;
  168. cb.pcCounter++;
  169. addToPCString(pcStr, childIndiv, parentIndiv, true);
  170. parent.treeLevel = child.treeLevel + 1;
  171. if (bindingMade.equals("Alter")) {
  172. cb.level = parent.treeLevel;
  173. if (dyad != null) dyad.path.add(parentIndiv);
  174. }
  175. } // end of else-if-kid-already-exists
  176. else { // both already exist & bound; verify they are recorded as parent/child & meet constraints
  177. // 'cuz both are already bound, there's no point in ever repeating this level -- max both flags
  178. kidFlag = 6;
  179. parFlag = 2;
  180. if ((childIndiv.birthFamily == null) && (parentIndiv.marriages.isEmpty())) {
  181. fam = new Family(parentIndiv, parent.argName, constraints.divorce);
  182. fam.addChild(childIndiv);
  183. } // end of if-birthFamily-not-created-and-parent-unmarried
  184. else if (childIndiv.birthFamily == null) { // parent has an existing marriage
  185. fam = (Family)parentIndiv.marriages.get(0);
  186. fam.addChild(childIndiv);
  187. } // end of birthFamily-not-created-but-parent-married
  188. else if ((childIndiv.birthFamily != null) && (parentIndiv.marriages.isEmpty())) {
  189. // BirthFam may have a dummy-parent in it that parent can replace
  190. fam = childIndiv.birthFamily;
  191. if (! (childIndiv.birthFamily.subForDummyParent(parentIndiv))) // not-compatible
  192. return false;
  193. } // end of if-birthFamily-created-and-parent-unmarried
  194. else { // birthFam-exists-and-parent-already-married. Our only hope is that they are compatible.
  195. fam = childIndiv.birthFamily;
  196. if (! (parentIndiv.marriages.contains(childIndiv.birthFamily))) // if compatible, do nothing
  197. return false;
  198. } // end of birthFam-exists-and-parent-already-married
  199. fam.checkFamDOBs();
  200. if ((fam != null) && (fam.getMarriageDate().length() < 4)) fam.generateMarriageDate();
  201. cb.pcCounter++; // even though no one was bound, we have successfully traversed a link
  202. // Since neither arg was 'pre-Bound' we'll emit a PC-String in same form as this
  203. if (predicate.name.equals("father") || predicate.name.equals("mother") || predicate.name.equals("parent"))
  204. addToPCString(pcStr, childIndiv, parentIndiv, true);
  205. else addToPCString(pcStr, parentIndiv, childIndiv, false);
  206. } // end of else-they-both-already-exist
  207. // If we get this far, we have not (yet) failed (returned false).
  208. // If we can successfully recurse on remaining literals, we succeed (return true).
  209. // If not, then we must call this method again with badBindings & the updated flags
  210. Literal next = null;
  211. ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
  212. while ((next == null) && ((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)))
  213. next = cb.pop(remLitsCopy, starStuffCopy, bindings, kinTerm); // pop returns the next processable literal
  214. if (next == null) { // at end of clause body. Check clause-level constraints.
  215. if (negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb))
  216. return true;
  217. } // end of at-end-of-clauseBody
  218. else if (next.findOrCreate(remLitsCopy, starStuffCopy, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
  219. return true;
  220. // Recursive descent or negatedConstraints failed. LiteralAbstract1.failReason tells us if failure to
  221. // find a conforming value for a UDP is the cause. If not, then it's 'regular' causes.
  222. // If the cause is a UDP, then try to pick a different UDP value & try again with current bindings.
  223. // If not, then retract current binding & try again.
  224. // if (Context.breakFlag) System.out.println("F/C_BirthLink FAILS on " + this);
  225. if ((LiteralAbstract1.failReason != null) && (bindingMade != null)) {
  226. Variable whoVar = child; // bindingMade has to be one of them
  227. if (parent.argName.equals(bindingMade)) whoVar = parent;
  228. TreeMap thisUDMap = (TreeMap)constraints.userDefined.get(whoVar);
  229. String failure = LiteralAbstract1.failReason;
  230. if ((thisUDMap != null) && (thisUDMap.get(failure) != null) &&
  231. (! (thisUDMap.get(failure) instanceof Constant))) {
  232. // it was a StarProp failure, and this arg has a constraint on that StarProp,
  233. // and the argument defining its constraint is not a Constant (ergo, it's a MathVar or a Variable for a person)
  234. if (thisUDMap.get(failure) instanceof MathVariable) {
  235. MathVariable argForUDPVal = (MathVariable)thisUDMap.get(failure);
  236. // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
  237. LiteralAbstract1.failReason = null;
  238. while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
  239. if (((next != null) &&
  240. next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
  241. || ((next == null) &&
  242. negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
  243. return true;
  244. } // end of while-loop. In this loop, newUDPVal tries to find a new conforming value
  245. // for this UDP. If it succeeds, then it calls find/create (or negatedConstraints)
  246. // in an attempt to complete the generation of this example. If that succeeds,
  247. // it returns true; if that fails, it picks another and tries again. If all possible UDP values
  248. // are used up without success, the loop ends and we go on.
  249. } // end of it-was-a-MathVariable
  250. else { // it-must-be-a-Variabe-for-a-person
  251. Variable argForUDPVal = (Variable)thisUDMap.get(failure);
  252. // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
  253. LiteralAbstract1.failReason = null;
  254. while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
  255. if (((next != null) &&
  256. next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
  257. || ((next == null) &&
  258. negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
  259. return true;
  260. } // end of while-loop.
  261. } // end of it-must-be-a-Variabe-for-a-person
  262. } // end of there is a UDP constraint for this bound-arg
  263. } // end of failed-due-to-a-UDP-value
  264. if (pcStr.size() >= 1) pcStr.remove(pcStr.size() -1); // retract the PC-String addition
  265. if (dyad != null && dyad.path.size() > 0) dyad.path.remove(dyad.path.size() -1);
  266. if (bindingMade != null) cb.pcCounter--; // if we incremented a counter, un-do that.
  267. // retract any binding made - put it on BadBindings list; retract property bindings made here.
  268. updateBindingsEtc(bindings, badBindings, bindingMade, argBound, starBindings, sbSize);
  269. if ((kidFlag < 6) && (parFlag < 2)) {
  270. if (findOrCreateBirthLink(parSex, kidSex, parArg, remLits, starStuff, bindings, badBindings,
  271. starBindings, constraints, kidFlag, parFlag, true, kinTerm, cb, pcStr, dyad))
  272. return true;
  273. // if we get this far, all binding attempts have failed. Pass failure up to next higher level.
  274. // keepBB determines whether we retain our record of a badBinding at this level.
  275. // If we're about to send a FAIL back to a higher-level literal in the chain, we want to
  276. // erase them. But if we're FAILing back to an earlier iteration at this level, keep them.
  277. // In EITHER case, make sure any property bindings have been undone.
  278. updateBindingsEtc(bindings, badBindings, null, null, starBindings, sbSize);
  279. }
  280. if (! keepBB) {
  281. badBindingsRemove(bindingMade, argBound, badBindings);
  282. Context.current.resetTo(resetInd, resetFam);
  283. } // end of don't-keep-badBindings
  284. return false;
  285. // end of recursive-descent-or-negatedConstraints-failed
  286. } // end of method findOrCreateBirthLink
  287. ArrayList<Object> resolveOppo(TreeMap bindings, ConstraintObj constraints, Variable argVar) throws KSConstraintInconsistency {
  288. // If there are no gender constraints on the variable argVar, there's nothing to resolve.
  289. // If the gender constraints contain either M or F, there's nothing to resolve.
  290. // If they contain any "Opposite of" or "Same as" constraints, chase & resolve if possible
  291. ArrayList<Object> answer = (ArrayList<Object>)constraints.gender.get(argVar.argName), otherConstrLst;
  292. if (answer == null) return answer;
  293. boolean male = false, female = false;
  294. ArrayList<Object> oppo = new ArrayList<Object>(), same = new ArrayList<Object>();
  295. String constraint, sameSexVarName, oppoSexVarName;
  296. Individual sameSexInd, oppoSexInd;
  297. for (int i=0; i < answer.size(); i++) {
  298. constraint = (String)answer.get(i);
  299. if (constraint.equals("F")) female = true;
  300. else if (constraint.equals("M")) male = true;
  301. else if (constraint.indexOf("Opposite") > -1) oppo.add(constraint.substring(12));
  302. else if (constraint.indexOf("Same") > -1) same.add(constraint.substring(8));
  303. } // end of for-i=each-constraint
  304. if (male && female) throw new KSConstraintInconsistency("for " + argVar);
  305. if (male || female) return answer;
  306. if (! same.isEmpty()) {
  307. for (int j=0; j < same.size(); j++) {
  308. sameSexVarName = (String)same.get(j);
  309. sameSexInd = (Individual)bindings.get(sameSexVarName);
  310. if (sameSexInd != null) {
  311. if (sameSexInd.gender.equals("F")) female = true;
  312. else if (sameSexInd.gender.equals("M")) male = true; }
  313. else {
  314. otherConstrLst = (ArrayList<Object>)constraints.gender.get(sameSexVarName);
  315. if (otherConstrLst.contains("F")) female = true;
  316. else if (otherConstrLst.contains("M")) male = true;
  317. } // end of else-sameSexVarName-not-bound-yet
  318. } // end of for-j=each-same-sex-variable-name
  319. } // end of same-is-not-empty
  320. if (! oppo.isEmpty()) {
  321. for (int j=0; j < oppo.size(); j++) {
  322. oppoSexVarName = (String)oppo.get(j);
  323. oppoSexInd = (Individual)bindings.get(oppoSexVarName);
  324. if (oppoSexInd != null) {
  325. if (oppoSexInd.gender.equals("F")) male = true;
  326. else if (oppoSexInd.gender.equals("M")) female = true; }
  327. else {
  328. otherConstrLst = (ArrayList<Object>)constraints.gender.get(oppoSexVarName);
  329. if (otherConstrLst.contains("M")) female = true;
  330. else if (otherConstrLst.contains("F")) male = true;
  331. } // end of else-oppoSexVarName-not-bound-yet
  332. } // end of for-j=each-oppo-sex-variable-name
  333. } // end of oppo-is-not-empty
  334. if (male && female) throw new KSConstraintInconsistency("Both M & F required for " + argVar);
  335. if (male) {
  336. answer = new ArrayList<Object>();
  337. answer.add("M");
  338. } // end of if-male
  339. if (female) {
  340. answer = new ArrayList<Object>();
  341. answer.add("F");
  342. } // end of if-female
  343. return answer;
  344. } // end of method resolveOppo
  345. public boolean newUDPVal(String failedProp, Variable theVar, String bindingMade, TreeMap bindings,
  346. ArrayList<Object> starBindings, ConstraintObj constraints, ClauseBody cb)
  347. throws KSInternalErrorException, KSBadHornClauseException, ClassNotFoundException, KSConstraintInconsistency {
  348. // Existing value for person's StarProp did not work out. Return true if a different conforming
  349. // value can be assigned.
  350. Individual ind = (Individual)bindings.get(bindingMade);
  351. UserDefinedProperty udp = (UserDefinedProperty)ind.userDefinedProperties.get(failedProp);
  352. if (udp == null) throw new KSInternalErrorException("Null UDP in Literal.newUDPVal for " + bindingMade);
  353. theVar.updatePriorVals(theVar.getVal());
  354. // Remove the old values, but retain the record of this value as a priorValue
  355. theVar.clearVal();
  356. Iterator iter = starBindings.iterator();
  357. while (iter.hasNext()) {
  358. StarPropertyBinding spb = (StarPropertyBinding)iter.next();
  359. if ((spb.personBound == ind) && (spb.starPropName.equals(failedProp)))
  360. iter.remove();
  361. } // end of loop thru starBindings
  362. return ind.findConformingValue(failedProp, (Argument)theVar, starBindings, bindings, constraints, "commit", cb);
  363. } // end of method newUDPVal
  364. void badBindingsRemove(String bindingMade, Argument argBound, TreeMap badBindings) {
  365. if (bindingMade == null) return;
  366. badBindings.remove(bindingMade);
  367. if (argBound instanceof Variable) ((Variable)argBound).priorValues = null;
  368. } // end of method badBindingsRemove()
  369. boolean negatedConstraintsSatisfied(ArrayList<Object> starStuff, TreeMap bindings, TreeMap badBindings, ArrayList<Object> starBindings,
  370. ConstraintObj constraints, String kinTerm, ClauseBody cb)
  371. throws KSInternalErrorException, KSBadHornClauseException, ClassNotFoundException {
  372. // Check to see if any of the ClauseBodies in the Negated Constraint are true. If any one
  373. // of them is true, the test is failed and we return false.
  374. // if (Context.breakFlag) Context.breakpoint();
  375. if ((constraints.negated == null) || (constraints.negated.isEmpty())) return true;
  376. Individual ego = (Individual)bindings.get("Ego");
  377. ClauseBody cbNeg;
  378. ArrayList<Object> bodyCopy;
  379. TreeMap bindingsCopy = new TreeMap(bindings);
  380. ConstraintObj constraintsCopy;
  381. for (int i=0; i < constraints.negated.size(); i++) {
  382. cbNeg = (ClauseBody)constraints.negated.get(i);
  383. constraintsCopy = new ConstraintObj(constraints);
  384. constraintsCopy.negated = new ArrayList<Object>(); // to prevent infinite recursion
  385. // Any restrictions on variables induced by a negated clause should apply only to a
  386. // "deep copy" of the args found in the main clausebody, not the main args themselves.
  387. bodyCopy = new ArrayList<Object>();
  388. for (int k=0; k < cbNeg.body.size(); k++)
  389. bodyCopy.add(((Literal)cbNeg.body.get(k)).copy());
  390. // Keep all current constraints except the negated ones, and add any new constraints
  391. // (including negated ones) appearing in cbNeg.
  392. try {
  393. for (int j=0; j < bodyCopy.size(); j++)
  394. if (! (((Literal)bodyCopy.get(j)).constraintCheck(ego.gender, constraintsCopy, new ArrayList<Object>(), starStuff)))
  395. throw new KSConstraintInconsistency(" ");
  396. LiteralAbstract1.negativeConstraintPhase = true;
  397. if (! LiteralAbstract1.finalConstraintCheck(ego.gender, bindingsCopy, constraintsCopy, bodyCopy, new ArrayList<Object>(), starStuff))
  398. throw new KSConstraintInconsistency(" ");
  399. LiteralAbstract1.negativeConstraintPhase = false;
  400. // finalConstraintCheck does post-processing & a final conflict-check; the negConstraints flag influences its logic
  401. Literal next = null;
  402. while (((bodyCopy.size() > 0) || (starStuff.size() > 0)) && (next == null))
  403. next = cb.pop(bodyCopy, starStuff, bindingsCopy, kinTerm); // next = first non-constraint literal in body
  404. if (next == null)
  405. throw new KSBadHornClauseException("No processable literals in negated clause:/n not(" + cbNeg.body + ")");
  406. else if (constraintsCopy.allowCreation) {
  407. LiteralAbstract1.negativeConstraintPhase = true;
  408. if (next.findOrCreate(bodyCopy, starStuff, bindingsCopy, badBindings, starBindings, constraintsCopy, kinTerm, cb, new ArrayList<Object>(), null)) {
  409. // We don't keep the PC-String from a negated Constraint, so we pass a throw-away empty list
  410. LiteralAbstract1.negativeConstraintPhase = false;
  411. return false;
  412. }else LiteralAbstract1.negativeConstraintPhase = false;
  413. } // end of if-creation-is-allowed
  414. else if (next.fillInNames_bool(kinTerm, bodyCopy, starStuff, cbNeg, bindingsCopy, constraintsCopy, null, new ArrayList<Object>()))
  415. return false;
  416. } catch (KSConstraintInconsistency e) { }
  417. // If a ConstraintInconsistency occurs here, it means the constraints alone are enough to
  418. // make this ClauseBody impossible. So treat this the same as a failure by findOrCreate;
  419. // go on to the next clauseBody (if any).
  420. } // end of for-i=each-negated-constraint
  421. return true;
  422. } // end of method negatedConstraintsSatisfied
  423. void updateBindingsEtc(TreeMap bindings, TreeMap badBindings, String bindingMade, Argument argBound,
  424. ArrayList<Object> starBindings, int sbSize) {
  425. // This method is invoked when backtracking is about to occur. We must retract the current bindingMade,
  426. // & add it to badBindings. Any property bindings made in this round are un-done.
  427. StarPropertyBinding spb;
  428. UserDefinedProperty udp;
  429. // First Process StarBindings. 'Normal' SPBs reflect a linking and binding event.
  430. // But SPBs w/ PersonBound == null reflect addition of a value via assureContainedBy
  431. for (int i = starBindings.size() - 1; i >= sbSize; i--) {
  432. spb = (StarPropertyBinding)starBindings.get(i);
  433. if (spb.mathVarBound != null) {
  434. for (int j=0; j < spb.valsAssigned.size(); j++)
  435. spb.mathVarBound.removeVal(spb.valsAssigned.get(j));
  436. if (spb.personBound != null) // Person's UDP & MathVar were linked
  437. spb.mathVarBound.unLink();
  438. }else if (spb.variableBound != null) {
  439. for (int j=0; j < spb.valsAssigned.size(); j++)
  440. spb.variableBound.removeVal(spb.valsAssigned.get(j));
  441. if (spb.personBound != null) {
  442. udp = (UserDefinedProperty)spb.personBound.userDefinedProperties.get(spb.starPropName);
  443. udp.value = setDifference(udp.value, spb.valsAssigned);
  444. } // end of an-Individual's-property-was-bound
  445. } // end of it's-a-Variable
  446. starBindings.remove(i);
  447. } // end of loop thru starBindings
  448. // Next Process BadBindings.
  449. if (bindingMade != null) {
  450. ArrayList<Object> badList = (ArrayList<Object>)badBindings.get(bindingMade);
  451. if (badList == null) badList = new ArrayList<Object>();
  452. Object bMade = bindings.get(bindingMade); // a MathVar is bound to its values list
  453. if (bMade instanceof ArrayList) badList.addAll((ArrayList<Object>)bMade);
  454. else badList.add(bMade);
  455. if (bMade instanceof Individual) {
  456. if (((Individual)bMade).node.appearances > 1) ((Individual)bMade).node.appearances--;
  457. else ((Individual)bMade).node = null;
  458. }
  459. badBindings.put(bindingMade, badList);
  460. bindings.remove(bindingMade);
  461. // We unLink a MathVar if it is removed from Bindings
  462. // if (argBound instanceof MathVariable) ((MathVariable)argBound).unLink();
  463. // REMOVED ON THEORY THAT SPBs WILL MANAGE UN-LINKING
  464. }
  465. } // end of method updateBindingsEtc
  466. public void addToPCString(ArrayList<Object> pcStr, Individual preBound, Individual newBound, boolean preIsKid) {
  467. // Create a standardized literal expressing the BirthLink relationship of newBound to preBound.
  468. // NewBound should be arg0 of that literal, and preBound should be arg1.
  469. String preBoundTag = "#" + preBound.serialNmbr, newBoundTag = "#" + newBound.serialNmbr,
  470. pc, newBoundSex = newBound.gender;
  471. if (preIsKid) { // must create a parental pc
  472. if (newBoundSex.equals("M")) pc = "Fa";
  473. else if (newBoundSex.equals("F")) pc = "Mo";
  474. else pc = "P";
  475. }else { // Must create a child pc
  476. if (newBoundSex.equals("M")) pc = "So";
  477. else if (newBoundSex.equals("F")) pc = "Da";
  478. else pc = "C"; }
  479. pcStr.add(pc + "(" + newBoundTag + "," + preBoundTag + ")");
  480. } // end of method addToPCString for BirthLinks
  481. public void addToPCString(ArrayList<Object> pcStr, boolean divReq, Individual preBound, Individual newBound) {
  482. // Create a standardized literal expressing the SpouseLink relationship of newBound to preBound.
  483. // NewBound should be arg0 of that literal, and preBound should be arg1.
  484. String preBoundTag = "#" + preBound.serialNmbr, newBoundTag = "#" + newBound.serialNmbr,
  485. pc, newBoundSex = newBound.gender;
  486. if (newBoundSex.equals("M")) pc = "Hu";
  487. else if (newBoundSex.equals("F")) pc = "Wi";
  488. else pc = "Sp";
  489. pcStr.add(pc + "(" + newBoundTag + "," + preBoundTag + ")");
  490. } // end of method addToPCString for SpouseLink
  491. boolean findOrCreateStarLink(ArrayList<Object> remLits, ArrayList<Object> starStuff, TreeMap bindings, TreeMap badBindings, ArrayList<Object> starBindings,
  492. ConstraintObj constraints, int tryFlag, boolean keepBB, String kinTerm, ClauseBody cb, ArrayList<Object> pcStr, Dyad dyad)
  493. throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
  494. // The current literal is a *-predicate declaring a value (via a constant or variable) for a person's UDP.
  495. // Arg0 is the value (a Variable/MathVariable/Constant); Arg1 is the Variable for the person whose UDP's value must equal arg0.
  496. // *-predicates can serve as constraints, or can define a trait that "links" 2 individuals in the chain from Ego to Alter.
  497. // Only the latter case is handled here; constraints were handled earlier in cb.constraintCheck.
  498. // NOTE: The semantics of a *-predicate are simplistic. The literal "*friends(X, Gary)" means that the MathVariable X has a
  499. // value exactly equal to the value of Gary's UserDefinedProperty *friends. Sub-sets and super-sets are not considered equal.
  500. // The math operator "contains" expresses sub-set relationships, if desired.
  501. int resetInd = Context.current.indSerNumGen, resetFam = Context.current.famSerNumGen, sbSize = starBindings.size();
  502. String bindingMade = null;
  503. MathVariable mathVar = null;
  504. Constant konstant = null;
  505. Variable personVar = (Variable)args.get(1), valPerVar = null;
  506. Individual person = (Individual)bindings.get(personVar.argName), valPer = null; // null = that variable not yet bound
  507. // if (Context.breakFlag) Context.breakpoint();
  508. // arg0 is either a MathVariable, a Variable, or a Constant.
  509. UserDefinedProperty udp;
  510. Argument arg0 = (Argument)args.get(0), argBound = null;
  511. if (arg0 instanceof MathVariable) mathVar = (MathVariable)arg0;
  512. else if (arg0 instanceof Constant) konstant = (Constant)arg0;
  513. else { // must be a Variable
  514. valPerVar = (Variable)arg0;
  515. valPer = (Individual)bindings.get(valPerVar.argName); // may be null if this Variable not yet bound
  516. }
  517. if (LiteralAbstract1.negativeConstraintPhase) {
  518. // Person and valPer may have been bound earlier in a 'positive' phase, and carried (via bindings
  519. // list) into a 'negatedConstraintsSatisfied' phase. So double check constraints. Use the _Strictly_
  520. // versions,'cuz we don't want to change anything on a bound arg/object pair.
  521. if ((person != null) && (! person.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)))
  522. return false;
  523. if ((valPer != null) && (! valPer.meetsConstraintsStrictly(valPerVar, constraints, bindings, starBindings)))
  524. return false;
  525. } // end of if-negativeConstraintPhase
  526. if ((person != null) && ((mathVar != null) || (konstant != null))) {
  527. // person-is-bound-and-arg0-is-a-mathVar-or-constant
  528. udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
  529. if ((udp.value.size() > 1) && (udp.singleValue)) // invalid condition: Panic!
  530. throw new KSInternalErrorException("In findOrCreateStarLink: encountered single-valued UDP with multiple values");
  531. // findConformingValue will transfer person's value(s) to the mathVar's value(s) if person has any and they
  532. // are valid values for the mathVar. Or it will copy the constant's (or the mathVar's) values to the udp. If neither mathVar nor person has a value,
  533. // then it will invent a conforming value. If no conforming value is possible, it returns 'false', otherwise 'true.'
  534. if (! person.findConformingValue(predicate.name, arg0, starBindings, bindings, constraints, "commit", cb)) {
  535. LiteralAbstract1.failReason = predicate.name;
  536. return false;
  537. } // end of failed to find a conforming value.
  538. // Found a conforming value. Done.
  539. bindingMade = arg0.argName;
  540. if (dyad != null) dyad.path.add(person);
  541. if (person.node == null) person.node = new Node();
  542. else person.node.appearances++;
  543. argBound = arg0;
  544. person.yoke(mathVar, null, konstant, null, udp, bindingMade, bindings, starBindings);
  545. } // end of person-is-bound-and-arg0-is-a-mathVar-or-constant
  546. else if ((person != null) && (valPerVar != null)) {
  547. // person-is-bound-and-value-is-also-a-person
  548. udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
  549. if (valPer != null) { } // Do nothing. We validity-checked both of them above & all is OK.
  550. else if (! udp.typ.equals("individual"))
  551. throw new KSInternalErrorException("In findOrCreateStarLink: Personal variable '" + valPerVar + "' used for UDP of type " + udp.typ);
  552. else if (! person.findConformingValue(predicate.name, arg0, starBindings, bindings, constraints, "commit", cb)) {
  553. LiteralAbstract1.failReason = predicate.name;
  554. return false;
  555. } // end of failed to find a conforming value.
  556. // Found a conforming value. Done.
  557. bindingMade = valPerVar.argName; // We bind valPerVar to the person who conforms.
  558. if (dyad != null) dyad.path.add(valPer);
  559. argBound = valPerVar;
  560. if (valPer.node == null) valPer.node = new Node();
  561. else valPer.node.appearances++;
  562. bindings.put(valPerVar.argName, valPer); // Binding it extends the chain of relations
  563. } // end of person-is-bound-and-value-is-also-a-person
  564. else if ((person == null) && ((mathVar != null) || (konstant != null))) {
  565. // Person-is-unbound-and-mathVar-or-constant-is-bound. Call a Context instance method to find a person who has a value equal to
  566. // the mathVar/Constant's value, if any. If none is found, create one and give him this (or a conforming) value.
  567. person = Context.current.findConformingPerson(arg0, predicate.name, personVar, constraints, badBindings,
  568. starBindings, bindings); // null -> found none
  569. if (person != null) createPersonalStarLink(person, predicate.name, starBindings);
  570. else {
  571. String indNam = "Hypothetical Person", gender = "?", birthdate = "Jan 1, 1970"; // neuter gender forces constructor to search constraints
  572. BoolFlag failFlag = new BoolFlag(false);
  573. person = new Individual(indNam, gender, null, birthdate, ((Argument)args.get(1)).argName, null, bindings,
  574. starBindings, constraints, personVar, failFlag, cb);
  575. if (failFlag.value) {
  576. LiteralAbstract1.failReason = failFlag.reason;
  577. return false;
  578. }else createPersonalStarLink(person, predicate.name, starBindings);
  579. }
  580. // If we're here, an appropriate person was found
  581. bindingMade = personVar.argName; // We bind personVar to the conforming person who can take on this UDP value.
  582. if (dyad != null) dyad.path.add(person);
  583. argBound = personVar;
  584. udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
  585. if (person.node == null) person.node = new Node();
  586. else person.node.appearances++;
  587. person.yoke(mathVar, null, konstant, personVar, udp, bindingMade, bindings, starBindings);
  588. } // end of Person-is-unbound-and-mathVar-or-constant-is-bound
  589. else if ((person == null) && (valPer != null)) {
  590. // person-is-unbound-and-valPerVar-is-bound. Call a Context instance method to find a person who has this value.
  591. // If none is found, create one and give him this value.
  592. person = Context.current.findConformingPerson(valPer, predicate.name, personVar, constraints, badBindings,
  593. starBindings, bindings); // null -> found none
  594. if (person == null) {
  595. String indNam = "Hypothetical Person", gender = "?", birthdate = "Jan 1, 1970";
  596. BoolFlag failFlag = new BoolFlag(false);
  597. person = new Individual(indNam, gender, null, birthdate, personVar.argName, null, bindings,
  598. starBindings, constraints, personVar, failFlag, cb);
  599. if (failFlag.value) {
  600. LiteralAbstract1.failReason = failFlag.reason;
  601. return false;
  602. }
  603. }
  604. // If we're here, an appropriate person was found
  605. bindingMade = personVar.argName; // We bind personVar to the conforming person who can take on this UDP value.
  606. if (dyad != null) dyad.path.add(person);
  607. bindings.put(personVar.argName, person); // Binding it extends the chain of relations
  608. if (person.node == null) person.node = new Node();
  609. else person.node.appearances++;
  610. argBound = personVar;
  611. } // end of person-is-unbound-and-valPerVar-is-bound
  612. else throw new KSInternalErrorException("findOrCreateStarLink found no value to assign."); // should never get here
  613. // OK. We've traversed a starLink successfully. Return or recurse.
  614. cb.starCounter++;
  615. // Now emit a PC-String like '*(<value>, <Person.serial#>)'
  616. String perSerial = "#" + person.serialNmbr, arg0Str;
  617. if (valPer != null) arg0Str = "#" + valPer.serialNmbr; // a Variable for a person is bound to the Individual
  618. else arg0Str = "value=" + ((ArrayList<Object>)bindings.get(arg0.argName)).get(0).toString();
  619. pcStr.add("*(" + arg0Str + "," + perSerial + ")");
  620. Literal next = null;
  621. ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
  622. while ((next == null) && ((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)))
  623. next = cb.pop(remLitsCopy, starStuffCopy, bindings, kinTerm); // pop returns the next processable literal
  624. if (next == null) { // at end of clause body. Check clause-level constraints.
  625. if (negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb))
  626. return true;
  627. } // end of at-end-of-clauseBody
  628. else if (next.findOrCreate(remLitsCopy, starStuffCopy, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
  629. return true;
  630. // Recursive descent or negatedConstraints failed. LiteralAbstract1.failReason tells us if failure to
  631. // find a conforming value for a person's UDP is the cause. If not, then it's 'regular' causes.
  632. // The failure can only involve a person in this literal if we bound either personVar or valPerVar.
  633. // If the cause is a UDP for one of those, then try to pick a different UDP value & try again with current bindings.
  634. // If not, then retract current binding & try again.
  635. // if (Context.breakFlag) System.out.println("F/C_StarLink FAILS on " + this);
  636. if ((LiteralAbstract1.failReason != null) && (bindingMade != null) &&
  637. (bindingMade.equals(personVar.argName) || ((valPerVar != null) && bindingMade.equals(valPerVar.argName)))) {
  638. String failure = LiteralAbstract1.failReason;
  639. Variable whoVar = personVar; // bindingMade has to be one of them
  640. if ((valPerVar != null) && bindingMade.equals(valPerVar.argName)) whoVar = valPerVar;
  641. TreeMap thisUDMap = (TreeMap)constraints.userDefined.get(whoVar);
  642. if ((thisUDMap != null) && (thisUDMap.get(failure) != null) &&
  643. (! (thisUDMap.get(failure) instanceof Constant))) {
  644. // it was a StarProp failure, and this arg has a constraint on that StarProp,
  645. // and the argument defining its constraint is not a Constant (ergo, it's a MathVar or a Variable for a person)
  646. if (thisUDMap.get(failure) instanceof MathVariable) {
  647. MathVariable argForUDPVal = (MathVariable)thisUDMap.get(failure);
  648. // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
  649. LiteralAbstract1.failReason = null;
  650. while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
  651. if (((next != null) &&
  652. next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
  653. || ((next == null) &&
  654. negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
  655. return true;
  656. } // end of while-loop. In this loop, newUDPVal tries to find a new conforming value
  657. // for this UDP. If it succeeds, then it calls find/create (or negatedConstraints)
  658. // in an attempt to complete the generation of this example. If that succeeds,
  659. // it returns true; if that fails, it picks another and tries again. If all possible UDP values
  660. // are used up without success, the loop ends and we go on.
  661. } // end of it-was-a-MathVariable
  662. else { // it-must-be-a-Variabe-for-a-person
  663. Variable argForUDPVal = (Variable)thisUDMap.get(failure);
  664. // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
  665. LiteralAbstract1.failReason = null;
  666. while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
  667. if (((next != null) &&
  668. next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
  669. || ((next == null) &&
  670. negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
  671. return true;
  672. } // end of while-loop.
  673. } // end of it-was-a-Variabe-for-a-person
  674. } // end of there is a UDP constraint for this bound-arg
  675. } // end of failed-due-to-a-UDP-value
  676. // retract any binding made - put it on BadBindings list. retract property bindings, too
  677. updateBindingsEtc(bindings, badBindings, bindingMade, argBound, starBindings, sbSize);
  678. cb.starCounter--; // un-do the counter increment
  679. if (argBound == personVar) undoPersonalStarLink(person, predicate.name, bindings);
  680. if (pcStr.size() >= 1) pcStr.remove(pcStr.size() -1); // retract the PC-String addition
  681. if (dyad != null && dyad.path.size() > 0) dyad.path.remove(dyad.path.size() -1);
  682. if (tryFlag++ < 2) {
  683. if (findOrCreateStarLink(remLits, starStuff, bindings, badBindings, starBindings, constraints,
  684. tryFlag, true, kinTerm, cb, pcStr, dyad))
  685. return true;
  686. // if we get this far, all binding attempts have failed. Pass failure up to next higher level.
  687. // keepBB determines whether we retain our record of badBindings at this level.
  688. // If we're about to send a FAIL back to a higher-level literal in the chain, we want to
  689. // erase them. But if we're FAILing back to an earlier iteration at this level, keep them.
  690. // In EITHER case, make sure any property bindings have been undone.
  691. updateBindingsEtc(bindings, badBindings, null, null, starBindings, sbSize);
  692. }
  693. if (! keepBB) {
  694. badBindingsRemove(bindingMade, argBound, badBindings);
  695. Context.current.resetTo(resetInd, resetFam);
  696. } // end of don't-keep-badBindings
  697. return false;
  698. // end of recursive-descent-or-negatedConstraints-failed
  699. } // end of method findOrCreateStarLink
  700. public void createPersonalStarLink(Individual person2, String predName, ArrayList<Object> starBindings)
  701. throws KSInternalErrorException {
  702. // Find the person, via starBindings, who has the link to person2
  703. for (int i = starBindings.size() -1; i >= 0; i--) {
  704. StarPropertyBinding spb = (StarPropertyBinding)starBindings.get(i);
  705. if (spb.starPropName.equals(predName) && spb.personBound != null && spb.personBound != person2) {
  706. Individual person1 = spb.personBound;
  707. if (person1.starLinks == null) person1.starLinks = new ArrayList<Object>();
  708. if (! person1.starLinks.contains(person2)) person1.starLinks.add(person2);
  709. if (person2.starLinks == null) person2.starLinks = new ArrayList<Object>();
  710. if (! person2.starLinks.contains(person1)) person2.starLinks.add(person1);
  711. return;
  712. } // end of found-a-match
  713. } // end of backwards loop thru SPBs
  714. Context.breakpoint();
  715. throw new KSInternalErrorException("Lit2.createPersonalStarLink failed to find origin of " + predName
  716. + "_link to " + person2);
  717. } // end of method createPersonalStarLink
  718. public void undoPersonalStarLink(Individual linkee, String predName, TreeMap bindings)
  719. throws KSInternalErrorException {
  720. // search bindings for a person who has a starLink of type predName to linkee
  721. Iterator boundIter = bindings.values().iterator();
  722. while (boundIter.hasNext()) {
  723. Object it = boundIter.next();
  724. if (it instanceof Individual) {
  725. Individual ind = (Individual) it;
  726. if (ind.starLinks

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