PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/code/ClauseBody.java

http://silkin.googlecode.com/
Java | 1285 lines | 1095 code | 42 blank | 148 comment | 387 complexity | fbc76c0e1dde9c536ea157bf3957f540 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.io.*;
  3. import java.text.*;
  4. /** A ClauseBody is just a list of literals, constituting one complete
  5. definition of the (predicate in the ClauseHead of the) kinship term.
  6. Multiple clause bodies comprise a disjunctive definition.
  7. @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
  8. */
  9. public class ClauseBody implements Serializable, Comparator {
  10. public static int seq = 0, seqTotal = 0, dups = 0, dupTotal = 0;
  11. public static String priorPred = "";
  12. public static int distanceLimit = 0;
  13. public static String[] arg0Guys = {"father", "husband", "son", "male", "brother", "half_brother",
  14. "step_brother", "step_father", "step_son"},
  15. arg0Gals = {"mother", "wife", "daughter", "female", "sister", "half_sister",
  16. "step_sister", "step_mother", "step_daughter"},
  17. exempts = {"male", "female", "equal", "not", "divorced", "dead", "gender",
  18. "lessThan", "greaterThan", "lessOrEql ", "greaterOrEql", "contains",
  19. "allowCreation", "parents", "siblings", "brother", "sister",
  20. "half_brother", "half_sister", "step_brother", "step_sister",
  21. "step_father", "step_mother", "children", "step_son",
  22. "step_daughter", "spice"},
  23. yin = {"male", "female", "elder", "younger", "brother", "sister"},
  24. yan = {"female", "male", "younger", "elder", "sister", "brother"};
  25. public static ArrayList<Object> arg0Males = loadMales(),
  26. arg0Females = loadFemales(),
  27. exemptPreds = loadExempt(),
  28. ying = loadYing(),
  29. yang = loadYang();
  30. /** <code>body</code> is an ArrayList<Object> of literals that make up the Right Hand Side of a Horn Clause.
  31. <code>expansionPath</code> is an ArrayList<Object> of strings that document the sequence of cultural
  32. kinTerms that were expanded into their all-Primitive meanings in the course of expanding THIS
  33. ClauseBody into its all-Primitive form.
  34. */
  35. ArrayList<Object> body, expansionPath, duplications;
  36. int seqNmbr;
  37. String genderOfAlter = "", pcString, pcStringStructural;
  38. KinTermDef ktd; // points to the enclosing KinTerm Definition
  39. /** During Example-Generation, this becomes true if recursion is encountered while
  40. interpreting this clause. Direct, indirect, and mutual recursion are detected. */
  41. boolean recursive = false;
  42. /** If the interpretation of this clause leads to the same node in a family tree as
  43. some other clause for the same kinTerm, then <code>duplicative</code> = true. */
  44. boolean duplicative = false;
  45. /** In Active Learning, we want to note which CBs matched postive examples of a kinTerm.
  46. true = 1 or more hits for the current kinTerm.*/
  47. boolean posHit = false;
  48. /** Contains all flags (strings within square brackets) found in the clauseBody during parsing. */
  49. public ArrayList<Object> flags;
  50. /** Level indicates the generation to which Alter belongs: 0 = Ego's generation, +1 = her father's generation,
  51. and -1 = her child's generation, etc. pcCounter is the count of all parent and child links traversed
  52. in reaching Alter. sCounter is the count of spouse links traversed to reach Alter, etc.*/
  53. int level = 0, pcCounter = 0, sCounter = 0, starCounter = 0, egoNum = -99;
  54. Library.BaseCB_Ptr baseCB_Ptr;
  55. public static ArrayList<Object> loadMales() {
  56. ArrayList<Object> result = new ArrayList<Object>();
  57. for (int i = 0; i < arg0Guys.length; i++) {
  58. result.add(arg0Guys[i]);
  59. }
  60. return result;
  61. } // end of static method loadMales
  62. public static ArrayList<Object> loadFemales() {
  63. ArrayList<Object> result = new ArrayList<Object>();
  64. for (int i = 0; i < arg0Gals.length; i++) {
  65. result.add(arg0Gals[i]);
  66. }
  67. return result;
  68. } // end of static method loadFemales
  69. public static ArrayList<Object> loadExempt() {
  70. ArrayList<Object> result = new ArrayList<Object>();
  71. for (int i = 0; i < exempts.length; i++) {
  72. result.add(exempts[i]);
  73. }
  74. return result;
  75. } // end of static method loadExempt
  76. public static ArrayList<Object> loadYing() {
  77. ArrayList<Object> result = new ArrayList<Object>();
  78. for (int i = 0; i < yin.length; i++) {
  79. result.add(yin[i]);
  80. }
  81. return result;
  82. } // end of static method loadYing
  83. public static ArrayList<Object> loadYang() {
  84. ArrayList<Object> result = new ArrayList<Object>();
  85. for (int i = 0; i < yan.length; i++) {
  86. result.add(yan[i]);
  87. }
  88. return result;
  89. } // end of static method loadYang
  90. ClauseBody() {
  91. body = new ArrayList<Object>();
  92. expansionPath = new ArrayList<Object>();
  93. flags = new ArrayList<Object>();
  94. } // end of constructor with no args
  95. /** Construct a new ClauseBody with one Literal in the body.
  96. @param lit the Literal to be placed in the body.
  97. */
  98. ClauseBody(Literal lit) {
  99. body = new ArrayList<Object>();
  100. expansionPath = new ArrayList<Object>();
  101. body.add(lit);
  102. flags = new ArrayList<Object>();
  103. } // end of constructor with one literal as arg
  104. /** Make a shallow copy of this ClauseBody. The new ClauseBody's fields will
  105. contain shallow copies of this one's fields.
  106. */
  107. public ClauseBody copy() {
  108. ClauseBody newCB = new ClauseBody();
  109. newCB.body = new ArrayList<Object>(body);
  110. newCB.genderOfAlter = genderOfAlter;
  111. newCB.duplications = duplications;
  112. newCB.duplicative = duplicative;
  113. newCB.pcString = pcString;
  114. newCB.pcStringStructural = pcStringStructural;
  115. newCB.recursive = recursive;
  116. newCB.ktd = ktd;
  117. newCB.level = level;
  118. newCB.egoNum = egoNum;
  119. newCB.pcCounter = pcCounter;
  120. newCB.sCounter = sCounter;
  121. newCB.starCounter = starCounter;
  122. newCB.flags = new ArrayList<Object>(flags);
  123. if (expansionPath == null) {
  124. newCB.expansionPath = new ArrayList<Object>();
  125. } else {
  126. newCB.expansionPath = new ArrayList<Object>(expansionPath);
  127. }
  128. newCB.baseCB_Ptr = baseCB_Ptr;
  129. return newCB;
  130. } // end of copy method
  131. /** Make a deep copy of this ClauseBody. The new ClauseBody's body will
  132. contain a deep copy of this one's.
  133. */
  134. public ClauseBody deepCopy() {
  135. ClauseBody newCB = new ClauseBody();
  136. newCB.body = new ArrayList<Object>();
  137. for (int i = 0; i < body.size(); i++) {
  138. Literal lit = (Literal) body.get(i);
  139. newCB.body.add(lit.copy());
  140. }
  141. newCB.genderOfAlter = genderOfAlter;
  142. newCB.duplications = duplications;
  143. newCB.duplicative = duplicative;
  144. newCB.pcString = pcString;
  145. newCB.pcStringStructural = pcStringStructural;
  146. newCB.recursive = recursive;
  147. newCB.ktd = ktd;
  148. newCB.level = level;
  149. newCB.egoNum = egoNum;
  150. newCB.pcCounter = pcCounter;
  151. newCB.sCounter = sCounter;
  152. newCB.starCounter = starCounter;
  153. newCB.flags = new ArrayList<Object>(flags);
  154. if (expansionPath == null) {
  155. newCB.expansionPath = new ArrayList<Object>();
  156. } else {
  157. newCB.expansionPath = new ArrayList<Object>(expansionPath);
  158. }
  159. newCB.baseCB_Ptr = baseCB_Ptr;
  160. return newCB;
  161. } // end of deepCopy method
  162. /** Add this Literal to the body of this ClauseBody.
  163. @param lit the Literal to be added to the body.
  164. */
  165. public void addLiteral(Literal lit) {
  166. body.add(lit);
  167. }
  168. // probably someday I'll need a "remove" method. Not Yet!
  169. /** Create a string representing this Horn Clause, in loose Prolog syntax.
  170. @return a String suitable for display or printing.
  171. */
  172. public String toString() {
  173. int size = body.size();
  174. String display = "", flagList = "", path = "", dups, prior, curr;
  175. for (int i = 0; i < size; i++) {
  176. display += body.get(i).toString();
  177. if (i < (size - 1)) {
  178. display += ", ";
  179. }
  180. }
  181. display += ".\n";
  182. if (flags.size() > 0) {
  183. Iterator flagIter = flags.iterator();
  184. while (flagIter.hasNext()) {
  185. flagList += "[" + (String) flagIter.next() + "], ";
  186. }
  187. } // end of if-there-are-flags
  188. if ((pcCounter + sCounter + starCounter) > 0) {
  189. path += ".\n Lvl=" + level + ", PC=" + pcCounter + ", S=" + sCounter + ", *=" + starCounter + ". ";
  190. }
  191. if (pcString != null && pcString.length() > 0) {
  192. path += "{" + pcString + "} ";
  193. }
  194. if (expansionPath.size() > 0) {
  195. Iterator pathIter = expansionPath.iterator();
  196. prior = (String) pathIter.next();
  197. if (path.length() > 5) {
  198. path += "[Expansion Path: " + prior;
  199. } else {
  200. path = ".\n [Expansion Path: " + prior;
  201. }
  202. while (pathIter.hasNext()) {
  203. curr = (String) pathIter.next();
  204. if (prior.equals("(not:")) {
  205. path += " ";
  206. } else if (!curr.equals(")")) {
  207. path += ", ";
  208. }
  209. prior = curr;
  210. path += prior;
  211. }
  212. path += "]";
  213. } // end of if-expansion-path-is-not-empty
  214. return flagList + display + path;
  215. } // end of over-riding toString method
  216. /** Create a string representing this Horn Clause, in strict Prolog syntax.
  217. @return a String suitable for parsing.
  218. */
  219. public String toThyString() throws KSInternalErrorException {
  220. int size = body.size();
  221. String display = " ", flagList = "", path = "", prior;
  222. for (int i = 0; i < size; i++) {
  223. display += body.get(i).toString() + (i < (size - 1) ? ", " : ".");
  224. }
  225. if (flags.size() > 0) {
  226. Iterator flagIter = flags.iterator();
  227. while (flagIter.hasNext()) {
  228. flagList += "[" + (String) flagIter.next() + "], ";
  229. }
  230. } // end of if-there-are-flags
  231. if (expansionPath.size() > 0) {
  232. Iterator pathIter = expansionPath.iterator();
  233. prior = (String) pathIter.next();
  234. path = ";; " + seqNmbr + "\n%" + prior;
  235. while (pathIter.hasNext()) {
  236. if (prior.equals("(not:")) {
  237. path += " ";
  238. } else {
  239. path += ", ";
  240. }
  241. prior = (String) pathIter.next();
  242. if (prior.equals(")")) {
  243. path = path.substring(0, path.length() - 2);
  244. }
  245. path += prior;
  246. }
  247. path += "%\n";
  248. path += " Lvl=" + level + ", PC=" + pcCounter + ", S=" + sCounter + ", Star=" + starCounter + ", ";
  249. path += "{" + (pcString == null || pcString.length() == 0 ? "None" : pcString) + "} \n";
  250. } // end of if-expansion-path-is-not-empty
  251. return path + flagList + display;
  252. } // end of method toThyString()
  253. String toXML(String bacer) {
  254. String s = bacer + "<clause>\n";
  255. for (int i=0; i < body.size(); i++) {
  256. Literal lit = (Literal)body.get(i);
  257. s += lit.toXML(bacer + "\t");
  258. }
  259. s += "\n" + bacer + "</clause>\n";
  260. return s;
  261. }
  262. String toSimpleHornClause() {
  263. String hornClaws = "";
  264. int last = body.size() - 1;
  265. for (int i = 0; i < last; i++) {
  266. Literal lit = (Literal) body.get(i);
  267. hornClaws += lit + ", ";
  268. }
  269. Literal lit = (Literal) body.get(last);
  270. return hornClaws + lit + ". ";
  271. }
  272. String toSILKString(String bacer) {
  273. String s = bacer + "<clause level=\"" + level + "\">\n",
  274. dblSpace = "\t\t";
  275. if (pcString != null && !pcString.isEmpty()) {
  276. s += bacer + "\t" + "<pc-string>" + pcString + "</pc-string>\n";
  277. }
  278. if (pcStringStructural != null && !pcStringStructural.isEmpty()) {
  279. s += bacer + "\t" + "<pc-string-structural>" + pcStringStructural
  280. + "</pc-string-structural>\n";
  281. }
  282. for (int i=0; i < body.size(); i++) {
  283. Literal lit = (Literal)body.get(i);
  284. s += lit.toSILKString(bacer + "\t") + "\n";
  285. }
  286. s += bacer + "</clause>\n";
  287. return s;
  288. }
  289. /** Expand this ClauseBody into one or more ClauseBodies that contain only predicates that
  290. are members of (@link PrimitiveCategory), and place them in <code>expandedDefs</code>.
  291. For example, assume the current domain theory contains the following definition:
  292. <p>
  293. <code>fee(Alter,Ego) :- son(Alter,Ego).
  294. <p> | daughter(Alter,Ego).</code>
  295. <p>
  296. that is: Alter is my 'fee' if he is either my 'son' or my 'daughter'. If this ClauseBody
  297. contains the literal <code>fee(X,Y)</code> then it will be expanded into 2 ClauseBodies;
  298. one will contain the "son" definition and one will contain the "daughter" definition.
  299. Both of them (after all literals have been expanded) will be stored in the <code>expandedDefs</code>
  300. for the current KinTermDef.
  301. @param hypo the current context.
  302. @param expandedDefs the location where completed expansions will be stored.
  303. @param kinTerm the cultural kinship term which this ClauseBody helps define.
  304. @param index the clause number of the base clause that we're expanding
  305. */
  306. public void expand(Context hypo, ArrayList<Object> expandedDefs, String kinTerm, int index)
  307. throws KSBadHornClauseException, KSInternalErrorException {
  308. ArrayList<Object> clauseSoFar = new ArrayList<Object>(), kinTermLst = new ArrayList<Object>(), recursLvlLst = new ArrayList<Object>(),
  309. save4Last = new ArrayList<Object>(), expPath = new ArrayList<Object>(),
  310. remainingLits = new ArrayList<Object>(body.subList(1, body.size()));
  311. kinTermLst.add(kinTerm);
  312. recursLvlLst.add(new Integer(0));
  313. expPath.add(kinTerm + ":" + index);
  314. // System.out.println("Expanding " + kinTerm + ":" + index);
  315. // if (kinTerm.equals("dad")) Context.breakpoint();
  316. Literal firstLit = (Literal) body.get(0);
  317. StackMarkerObj marker = new StackMarkerObj(kinTermLst, recursLvlLst);
  318. LiteralAbstract1.expansionSerial = 0;
  319. firstLit.expand(hypo, clauseSoFar, remainingLits, expandedDefs, save4Last, marker, this, expPath);
  320. return;
  321. } // end of method expand
  322. public boolean isExpansionOf(ClauseBody original) {
  323. if (original == null) {
  324. return true;
  325. }
  326. String origClauseNmbr = String.valueOf(original.seqNmbr);
  327. String firstExpansion = (String) expansionPath.get(0);
  328. int where = firstExpansion.indexOf(":");
  329. return (origClauseNmbr.equals(firstExpansion.substring(where + 1).trim()));
  330. }
  331. public int isExpandedFrom(ClauseBody original) {
  332. if (original == null) {
  333. return -1;
  334. }
  335. String firstExpansion = (String) expansionPath.get(0);
  336. int where = firstExpansion.indexOf(":");
  337. int origin = Integer.parseInt(firstExpansion.substring(where + 1).trim());
  338. return origin;
  339. }
  340. public void findAuxPreds(ArrayList<Object> auxPreds)
  341. throws KSParsingErrorException, KSConstraintInconsistency, KSInternalErrorException {
  342. // Find any cultural (non-primitive) predicates in the body of this base CB.
  343. // Retrieve the KTDs for all those, and put deep copies of them in auxPreds.
  344. // Recursively, find & deep-copy any non-primitives found in those auxPreds. (Compute a closure.)
  345. for (int i = 0; i < body.size(); i++) {
  346. Literal lit = (Literal) body.get(i);
  347. String lang = ktd.domTh.languageName,
  348. predName = lit.predicate.name;
  349. boolean duplicate = false;
  350. for (int j = 0; !duplicate && j < auxPreds.size(); j++) { // no duplicates
  351. KinTermDef pred = (KinTermDef) auxPreds.get(j);
  352. if (pred.kinTerm.equals(predName) && pred.domTh.languageName.equals(lang)) {
  353. duplicate = true;
  354. }
  355. }
  356. if (!duplicate && !DomainTheory.isPrimOrMacro(predName)
  357. && predName.indexOf("*") == -1) {
  358. int tagSpot = predName.indexOf("<F_aux>"); // maybe a prior aux was generalized
  359. String altName = (tagSpot > -1 ? predName.substring(0, tagSpot) : null);
  360. KinTermDef culturalPred = (KinTermDef) ktd.domTh.theory.get(predName); // look on original DT under predName
  361. if (culturalPred == null && altName != null) {
  362. culturalPred = (KinTermDef) ktd.domTh.theory.get(altName); // look on original DT under original name
  363. }
  364. if (culturalPred == null && altName != null) {
  365. culturalPred = (KinTermDef) DomainTheory.current.theory.get(predName); // look on Learner only under <F_aux> name
  366. } // Hopefully, one of those methods got it.
  367. if (culturalPred != null && culturalPred.definitions != null
  368. && culturalPred.definitions.size() > 0 && culturalPred.expandedDefs != null
  369. && culturalPred.expandedDefs.size() > 0) { // Easy
  370. KinTermDef culturalPredCopy = culturalPred.deepCopy();
  371. culturalPredCopy.kinTerm = predName; // Just in case we retrieved it under other name
  372. auxPreds.add(culturalPredCopy);
  373. for (int k = 0; k < culturalPred.definitions.size(); k++) {
  374. ((ClauseBody) culturalPred.definitions.get(k)).findAuxPreds(auxPreds);
  375. }
  376. } else {
  377. String fileName = Library.libraryDirectory + "Domain Theory Files/" + lang + ".thy";
  378. Linus dtLineServer = new Linus(fileName);
  379. Parser parzer = new Parser(new Tokenizer(Library.getDFA(), dtLineServer));
  380. try {
  381. culturalPred = parzer.parseKinTerm(predName, false);
  382. } catch (KSParsingErrorException pe) {
  383. if (altName != null) {
  384. culturalPred = parzer.parseKinTerm(altName, false);
  385. } else {
  386. throw pe;
  387. }
  388. }
  389. KinTermDef culturalPredCopy = culturalPred.deepCopy();
  390. culturalPredCopy.kinTerm = predName; // Just in case we retrieved it under other name
  391. try {
  392. ktd.domTh.addTerm(culturalPredCopy);
  393. } catch (KSParsingErrorException pe) {
  394. } // OK to over-write definition with complete KTD
  395. auxPreds.add(culturalPredCopy);
  396. for (int k = 0; k < culturalPredCopy.definitions.size(); k++) {
  397. ((ClauseBody) culturalPredCopy.definitions.get(k)).findAuxPreds(auxPreds);
  398. }
  399. } // end of else-parse-it
  400. } // end of found a cultural predicate
  401. } // end of loop thru definitions
  402. } // end of method findAuxPreds
  403. public void postToBaseSigString() throws KSInternalErrorException {
  404. // May be called only on an ExpandedDef, not on a base clause
  405. if (pcString == null) {
  406. throw new KSInternalErrorException("CB.postToBaseSigString called on CB with no pcString");
  407. }
  408. String firstExpansion = (String) expansionPath.get(0);
  409. int where = firstExpansion.indexOf(":");
  410. int baseCBNmbr = Integer.parseInt(firstExpansion.substring(where + 1).trim());
  411. ClauseBody baseCB = (ClauseBody) ktd.definitions.get(baseCBNmbr);
  412. if (baseCB.pcString == null) {
  413. baseCB.pcString = pcString;
  414. } else {
  415. baseCB.pcString += "_" + pcString;
  416. }
  417. } // end of method postToBaseSigString
  418. public void sortSigString() throws KSInternalErrorException {
  419. if (pcString == null || pcString.length() < 1) {
  420. throw new KSInternalErrorException("WARNING: Base clause " + ktd.domTh.languageName
  421. + ":" + ktd.kinTerm + ":" + seqNmbr + " has no non-duplicative expansions. Remove or fix it.");
  422. }
  423. TreeMap sorter = new TreeMap();
  424. String sigStr;
  425. int start = 0, end = pcString.indexOf("_");
  426. while (end > -1) {
  427. sigStr = pcString.substring(start, end);
  428. sorter.put(sigStr, sigStr);
  429. start = end + 1;
  430. end = pcString.indexOf("_", start);
  431. } // now get last one
  432. sigStr = pcString.substring(start);
  433. sorter.put(sigStr, sigStr);
  434. // Reassemble the sorted sigString
  435. Iterator iter = sorter.values().iterator();
  436. pcString = (String) iter.next();
  437. while (iter.hasNext()) {
  438. pcString += "_" + (String) iter.next();
  439. }
  440. } // end of method sortSigString()
  441. public void assignArgNames(Context ctxt) throws KSConstraintInconsistency {
  442. // Assign argNames to all the args, based on the assumption of a logical chain from Ego to Alter
  443. int argCodeIndex = 0;
  444. Variable nextVar = new Variable(LiteralAbstract1.argCodes[argCodeIndex++]);
  445. for (int i = 0; i < body.size(); i++) {
  446. Literal lit = (Literal) body.get(i);
  447. if (i == 0) {
  448. lit.args.add((body.size() > 1 ? nextVar : new Variable("Alter")));
  449. lit.args.add(new Variable("Ego"));
  450. } else if (i == body.size() - 1) {
  451. lit.args.add(new Variable("Alter"));
  452. lit.args.add(nextVar);
  453. } else {
  454. Variable arg1 = nextVar;
  455. nextVar = new Variable(LiteralAbstract1.argCodes[argCodeIndex++]);
  456. lit.args.add(nextVar); // new varName
  457. lit.args.add(arg1);
  458. }
  459. if (lit.predicate.name.equals("*")) { // Special processing for UDPs
  460. if (ctxt.userDefinedProperties == null || ctxt.userDefinedProperties.isEmpty()) {
  461. Context.breakpoint();
  462. }
  463. // TBA
  464. } // end of processing for UDPs
  465. } // end of loop thru body
  466. unifyVariables();
  467. } // end of method assignArgNames
  468. public void reassignArgNames(Context ctxt) throws KSConstraintInconsistency, KSInternalErrorException {
  469. // This method is like reassignArgNames_NewFront, but it handles the new (empty args) literal anywhere
  470. int insertionPt = -1;
  471. for (int i = 0; i < body.size(); i++) {
  472. Literal lit = (Literal) body.get(i);
  473. if (lit.args.isEmpty()) {
  474. if (insertionPt == -1) {
  475. insertionPt = i;
  476. } else {
  477. throw new KSConstraintInconsistency("CB.reassignArgNames got more than one lit with empty args.");
  478. }
  479. }
  480. } // end of i_loop
  481. if (insertionPt == -1) {
  482. throw new KSConstraintInconsistency("CB.reassignArgNames got no literals with empty args.");
  483. }
  484. if (insertionPt == 0) {
  485. reassignArgNames_NewFront(ctxt);
  486. return;
  487. }
  488. // Leave the literals ahead of the insertionPt alone. Note the arg names used.
  489. TreeMap old2New = new TreeMap(); // oldVarName => newVarName
  490. Literal lit = null;
  491. int argCodeIndex = 0;
  492. String nextVarName = LiteralAbstract1.argCodes[argCodeIndex++],
  493. mostRecentNewVarName = null,
  494. newVarName;
  495. for (int i = 0; i < insertionPt; i++) {
  496. lit = (Literal) body.get(i);
  497. for (int j = lit.args.size() - 1; j >= 0; j--) {
  498. String argName = ((Variable) lit.args.get(j)).argName;
  499. if (argName.equals(nextVarName)) {
  500. nextVarName = LiteralAbstract1.argCodes[argCodeIndex++];
  501. }
  502. old2New.put(argName, argName);
  503. mostRecentNewVarName = argName;
  504. } // end of j_loop
  505. } // end of i_loop
  506. // Give the inserted literal arg1 = previous end-of-chain, and arg0 = new variable
  507. lit = (Literal) body.get(insertionPt);
  508. lit.args.add(new Variable(nextVarName));
  509. lit.args.add(new Variable(mostRecentNewVarName));
  510. mostRecentNewVarName = nextVarName;
  511. nextVarName = LiteralAbstract1.argCodes[argCodeIndex++];
  512. // Give all following lits new variable argNames
  513. for (int i = insertionPt + 1; i < body.size(); i++) {
  514. lit = (Literal) body.get(i);
  515. Variable arg0Var = (Variable) lit.args.get(0);
  516. Variable arg1Var = (lit.args.size() == 2 ? (Variable) lit.args.get(1) : null);
  517. if (arg1Var != null) {
  518. newVarName = (String) old2New.get(arg1Var.argName);
  519. if (newVarName != null) {
  520. arg1Var.argName = newVarName;
  521. } else { // create a new var name for arg1
  522. old2New.put(arg1Var.argName, nextVarName);
  523. arg1Var.argName = nextVarName;
  524. nextVarName = LiteralAbstract1.argCodes[argCodeIndex++];
  525. }
  526. } // end of arg1Var not null
  527. newVarName = (String) old2New.get(arg0Var.argName);
  528. if (newVarName != null) {
  529. arg0Var.argName = newVarName;
  530. } else { // create a new var name for arg0
  531. old2New.put(arg0Var.argName, nextVarName);
  532. arg0Var.argName = nextVarName;
  533. mostRecentNewVarName = nextVarName;
  534. nextVarName = LiteralAbstract1.argCodes[argCodeIndex++];
  535. }
  536. }
  537. // Now change the mostRecentNewVarName to 'Alter'
  538. for (int j = 0; j < body.size(); j++) {
  539. lit = (Literal) body.get(j);
  540. for (int k = 0; k < lit.args.size(); k++) {
  541. Variable var = (Variable) lit.args.get(k);
  542. if (var.argName.equals(mostRecentNewVarName)) {
  543. var.argName = "Alter";
  544. }
  545. } // end of k_loop
  546. } // end of j_loop
  547. } // end of method reassignArgNames
  548. public void reassignArgNames_NewFront(Context ctxt) throws KSConstraintInconsistency, KSInternalErrorException {
  549. // Relabel the body literals' argNames into a nice progression
  550. // This method does NOT handle general negation or new variables introduced AFTER Alter.
  551. Literal lit = (Literal) body.get(0);
  552. if (lit.args.size() > 0) // First lit must be binary predicate with empty args
  553. {
  554. throw new KSInternalErrorException("CB.reassignArgNames_NewFront got front literal with existing args.");
  555. }
  556. int argCodeIndex = 0;
  557. String nextVarName = LiteralAbstract1.argCodes[argCodeIndex++],
  558. mostRecentNewVarName = null,
  559. newVarName;
  560. TreeMap old2New = new TreeMap(); // oldVarName => newVarName
  561. Variable arg1Var = new Variable("Ego"),
  562. arg0Var = ((body.size() == 1 ? new Variable("Alter") : new Variable(nextVarName)));
  563. lit.args.add(arg0Var);
  564. lit.args.add(arg1Var);
  565. if (body.size() == 1) {
  566. unifyVariables();
  567. return;
  568. }
  569. for (int i = 1; i < body.size(); i++) {
  570. lit = (Literal) body.get(i);
  571. arg0Var = (Variable) lit.args.get(0);
  572. arg1Var = (lit.args.size() == 2 ? (Variable) lit.args.get(1) : null);
  573. if (arg1Var != null) {
  574. newVarName = (String) old2New.get(arg1Var.argName);
  575. if (newVarName != null) {
  576. arg1Var.argName = newVarName;
  577. } else { // create a new var name for arg1
  578. old2New.put(arg1Var.argName, nextVarName);
  579. arg1Var.argName = nextVarName;
  580. nextVarName = LiteralAbstract1.argCodes[argCodeIndex++];
  581. }
  582. } // end of arg1Var not null
  583. newVarName = (String) old2New.get(arg0Var.argName);
  584. if (newVarName != null) {
  585. arg0Var.argName = newVarName;
  586. } else { // create a new var name for arg0
  587. old2New.put(arg0Var.argName, nextVarName);
  588. arg0Var.argName = nextVarName;
  589. mostRecentNewVarName = nextVarName;
  590. nextVarName = LiteralAbstract1.argCodes[argCodeIndex++];
  591. }
  592. if (lit.predicate.name.equals("*")) { // Special processing for UDPs
  593. if (ctxt.userDefinedProperties == null || ctxt.userDefinedProperties.isEmpty()) {
  594. Context.breakpoint();
  595. }
  596. // TBA
  597. } // end of processing for UDPs
  598. } // end of i_loop
  599. // Now change the mostRecentNewVarName to 'Alter'
  600. for (int j = 0; j < body.size(); j++) {
  601. lit = (Literal) body.get(j);
  602. for (int k = 0; k < lit.args.size(); k++) {
  603. Variable var = (Variable) lit.args.get(k);
  604. if (var.argName.equals(mostRecentNewVarName)) {
  605. var.argName = "Alter";
  606. }
  607. } // end of k_loop
  608. } // end of j_loop
  609. unifyVariables();
  610. } // end of method reassignArgNames_NewFront
  611. /** If this ClauseBody's literals contain multiple references to a single
  612. variable X, make sure that all references to X point to the same {@link Variable} object.
  613. Then implement all 'equal' predicates by doing global replacements in this ClauseBody. */
  614. public void unifyVariables() throws KSConstraintInconsistency {
  615. TreeMap bindery = new TreeMap();
  616. Counter cntr = new Counter();
  617. ArrayList<Object> bodyCopy = new ArrayList<Object>(body); // a "shallow copy" which points to the members of body.
  618. Literal lit = (Literal) bodyCopy.remove(0);
  619. try {
  620. lit.unifyVariables(bindery, bodyCopy, cntr);
  621. } catch (KSConstraintInconsistency ci) {
  622. throw new KSConstraintInconsistency(ci.toString().substring(39) + " in:\n" + this);
  623. }
  624. ArrayList<Object> eqLst = new ArrayList<Object>();
  625. for (int i = 0; i < body.size(); i++) {
  626. lit = (Literal) body.get(i);
  627. if (lit.predicate.name.equals("equal")) {
  628. eqLst.add(lit);
  629. }
  630. if (lit.predicate.name.equals("contains")) {
  631. checkValidity(lit);
  632. }
  633. } // end of for-loop
  634. if (eqLst.size() > 0) {
  635. globalReplace(eqLst, body);
  636. }
  637. } // end of method unifyVariables()
  638. public void checkValidity(Literal lit) throws KSConstraintInconsistency {
  639. // We have a 'contains' predicate. If the MathVar is single-valued, it should be an 'equal' predicate
  640. MathVariable var0 = (MathVariable) lit.args.get(0);
  641. String arg0Name = var0.argName, starPredName;
  642. UserDefinedProperty udp;
  643. Literal bodyLit;
  644. for (int i = 0; i < body.size(); i++) {
  645. bodyLit = (Literal) body.get(i);
  646. if ((bodyLit.predicate.name.substring(0, 1).equals("*"))
  647. && (arg0Name.equals(((Argument) bodyLit.args.get(0)).argName))) { // found-a-star-pred-binding-this-var
  648. starPredName = bodyLit.predicate.name;
  649. udp = (UserDefinedProperty) Context.current.userDefinedProperties.get(starPredName);
  650. if (udp == null) {
  651. String msg = "User-Defined Property '" + starPredName + "' is not defined for this domain.";
  652. throw new KSConstraintInconsistency(msg);
  653. } // end of udp-is-null => ERROR
  654. if (udp.singleValue) {
  655. String msg = "The variable '" + arg0Name + "' appears in '" + bodyLit + "' and in '"
  656. + lit + "' in:\n" + this + "\nThe former implies that " + arg0Name + " holds a single " + udp.typ
  657. + ", while the latter implies it is a list.\nNot permitted.";
  658. throw new KSConstraintInconsistency(msg);
  659. }
  660. } // end of found-a-star-pred-binding-this-var
  661. } // end of loop thru body
  662. } // end of method checkValidity
  663. public void globalReplace(ArrayList<Object> eqLst, ArrayList<Object> target) {
  664. Literal eqLit, lit2;
  665. Iterator iter;
  666. Argument arg1, in, out;
  667. for (int i = 0; i < eqLst.size(); i++) {
  668. eqLit = (Literal) eqLst.get(i);
  669. arg1 = (Argument) eqLit.args.get(1);
  670. if ((arg1.argName.equals("Alter"))
  671. || (arg1.argName.equals("Ego"))
  672. || (arg1 instanceof Constant)) {
  673. in = (Argument) eqLit.args.get(1); // never replace 'Alter', 'Ego' or a Constant.
  674. out = (Argument) eqLit.args.get(0);
  675. } else {
  676. in = (Argument) eqLit.args.get(0);
  677. out = (Argument) eqLit.args.get(1);
  678. }
  679. iter = target.iterator(); // at the top level, 'target' is really this ClauseBody's body
  680. while (iter.hasNext()) {
  681. lit2 = (Literal) iter.next();
  682. if (eqLit == lit2) {
  683. iter.remove();
  684. } else {
  685. for (int j = 0; j < lit2.args.size(); j++) {
  686. if (lit2.args.get(j) instanceof Literal) { // e.g. a 'not' predicate
  687. ArrayList<Object> newEq = new ArrayList<Object>(), newTarget = new ArrayList<Object>();
  688. newEq.add(eqLit);
  689. newTarget.add(lit2.args.get(j));
  690. globalReplace(newEq, newTarget);
  691. } // end of this-arg-is-a-Literal
  692. else if (lit2.args.get(j) == out) {
  693. lit2.args.set(j, in);
  694. }
  695. } // end of loop thru args of lit2
  696. }
  697. } // end of while-loop thru body
  698. } // end of for-loop thru eqLst
  699. } // end of method globalReplace
  700. /** Generate hypothetical people who have the relationship described in this ClauseBody.
  701. Add those people to the current context. Label the person called "Alter" in the clause
  702. with the <code>kinTerm</code> that this ClauseBody helps define.
  703. <p>
  704. This method is called only on a ClauseBody in the <code>extendedDefs</code> of a {@link KinTermDef}.
  705. Therefore, there are only Primitive predicates in the body.
  706. <p>
  707. When NOT doing simulatedDataGeneration, try to re-use an Ego from the egoBag, with all attributes assigned by prior clauses.
  708. If none of them work, try 1 male and 1 female 'fresh' Ego (no pre-existing attributes) & add them to the shared bag.
  709. If those don't work, give up.
  710. @param ktd the KinTermDef that this ClauseBody is part of.
  711. @param hypo the current context.
  712. @param egoBag collection of hypothetical persons (M & F) who can be 'ego.'
  713. @throws KSBadHornClauseException if this clause contains literals that are syntactically correct, but have logical flaws.
  714. @throws KSConstraintInconsistency if the constraints specified or implied in this clause are contradictory.
  715. @throws KSInternalErrorException if KS system has processed a literal improperly: send Bug Report!
  716. @throws ClassNotFoundException if an invalid type name is found in a user-defined property
  717. */
  718. public void generateExamples(Context hypo, ArrayList<Object> egoBag, Dyad dyad, Oracle orca)
  719. throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
  720. Individual ego = null;
  721. boolean oKay = false;
  722. int loops = 0, spares = 2,
  723. indivReset = hypo.indSerNumGen,
  724. famReset = hypo.famSerNumGen;
  725. String pad = "";
  726. ConstraintObj constraints = null;
  727. TreeMap bindings = null, badBindings;
  728. ArrayList<Object> genderStuff, starStuff, starBindings, eBagCopy = new ArrayList<Object>(egoBag), pcStr = null;
  729. Iterator bagIter = eBagCopy.iterator(), bodyIter;
  730. // CLAUSE COUNTER
  731. if (Library.parseClauseCounterOn && !ktd.kinTerm.equals(priorPred)) {
  732. if (!priorPred.equals("")) {
  733. pad = "";
  734. if (++seq < 10) {
  735. pad = " ";
  736. } else if (seq < 100) {
  737. pad = " ";
  738. }
  739. System.out.println(priorPred + ": " + pad + seq + " - " + dups + " = " + (seq - dups));
  740. seqTotal += seq;
  741. dupTotal += dups;
  742. }
  743. priorPred = ktd.kinTerm;
  744. dups = 0;
  745. }
  746. seq = seqNmbr;
  747. // END OF CLAUSE COUNTER
  748. // if (ktd.kinTerm.equals("hagaah")) Context.breakpoint();
  749. // else Context.breakFlag = false;
  750. // distanceLimit is enforced only during simDataGen for Leave-One-Out
  751. // Since nearly all PC_String components are 2 or 3 characters, we let
  752. // (floor(half the length of the PC_String)) -1 = a rough metric of relationship distance
  753. try {
  754. int stringDist = 0,
  755. pcStrLength = (pcString == null ? 0 : pcString.length());
  756. if (hypo.simDataGen) {
  757. stringDist = Math.min(Math.max((pcStrLength / 2) - 1, 0), Library.ClauseCounts.maxDist);
  758. }
  759. if (hypo.simDataGen && stringDist > distanceLimit) {
  760. return;
  761. }
  762. try {
  763. while (!oKay // && (loops++ == 0 || ! hypo.simDataGen) // Experimental
  764. && (bagIter.hasNext() || spares > 0)) { // the Big While Loop
  765. valRemover(body, new ArrayList<Object>()); // This will remove all "leftover" constraints & values from all variables in this ClauseBody
  766. if (bagIter.hasNext()) {
  767. ego = (Individual) bagIter.next();
  768. } else { // All existing Ego's have failed; make a fresh spare (M or F) for final try.
  769. if (spares > 1) {
  770. spares = 1;
  771. ego = new Individual("Ego", "F");
  772. } else {
  773. spares = 0;
  774. ego = new Individual("Ego", "M");
  775. }
  776. if (ktd.domTh.addressTerms) {
  777. ego.node.kinTermsAddr.add("Ego");
  778. } else {
  779. ego.node.kinTermsRef.add("Ego");
  780. }
  781. ego.setDateOfBirth("1970-01-01");
  782. }
  783. oKay = true;
  784. constraints = new ConstraintObj();
  785. genderStuff = new ArrayList<Object>();
  786. starStuff = new ArrayList<Object>();
  787. starBindings = new ArrayList<Object>();
  788. bodyIter = body.iterator();
  789. // if (loops++ > 0) System.out.println("With Ego = #" + ego.serialNmbr + ", re-trying " + ktd.kinTerm);
  790. // if (ktd.kinTerm.equals("dad")) System.out.println("With Ego #" + ego.serialNmbr + ", generating " + ktd.kinTerm + ":" + seqNmbr);
  791. /* if (Context.breakFlag) {
  792. System.out.println("With Ego = #" + ego.serialNmbr + ", generating " + ktd.kinTerm + ":" + seqNmbr);
  793. Context.breakpoint();
  794. } */
  795. while (oKay && bodyIter.hasNext()) // if any literal specifies ego gender ...
  796. {
  797. oKay = ((Literal) bodyIter.next()).constraintCheck(ego.gender, constraints, genderStuff, starStuff);
  798. }
  799. // constraintCheck, by side-effect, builds all constraints
  800. if (oKay) { // 1st OK
  801. bindings = new TreeMap();
  802. badBindings = new TreeMap();
  803. bindings.put("Ego", ego);
  804. oKay = LiteralAbstract1.finalConstraintCheck(ego.gender, bindings, constraints, body, genderStuff, starStuff);
  805. // finalConstraintCheck does post-processing & a final conflict-check.
  806. if (oKay) { // 2nd OK
  807. ArrayList<Object> bodyCopy = new ArrayList<Object>(body), starStuffCopy = new ArrayList<Object>(starStuff), empties;
  808. Literal next = null;
  809. while (((bodyCopy.size() > 0) || (starStuffCopy.size() > 0)) && (next == null)) {
  810. next = pop(bodyCopy, starStuffCopy, bindings, ktd.kinTerm); // next = first non-constraint literal in body
  811. }
  812. if (next == null) {
  813. throw new KSBadHornClauseException("No processable literals in:\n" + ktd.kinTerm + " :- " + lineBreaker(body));
  814. }
  815. // start the process with next. First, find any star-props for Ego
  816. Variable egoVar = null;
  817. for (int i = 0; i < next.args.size(); i++) {
  818. if (((Argument) next.args.get(i)).argName.equals("Ego")) {
  819. egoVar = (Variable) next.args.get(i);
  820. }
  821. }
  822. // Record which of Ego's star-props was blank before we started this CB.
  823. // Those are the only ones we can erase or change.
  824. empties = new ArrayList<Object>();
  825. UserDefinedProperty udp;
  826. if (ego.userDefinedProperties != null) {
  827. Iterator egoUDPiter = ego.userDefinedProperties.values().iterator();
  828. while (egoUDPiter.hasNext()) {
  829. udp = (UserDefinedProperty) egoUDPiter.next();
  830. if (udp.value.isEmpty()) {
  831. empties.add(udp.starName);
  832. }
  833. }
  834. }
  835. oKay = next.meetsStarSpecs(ego, egoVar, constraints, starBindings, bindings, "commit", this);
  836. if (oKay) { // 3rd OK
  837. // Find/Create will use level, pcCounter & sCounter. Re-initialize them to start.
  838. resetCounters();
  839. LiteralAbstract1.negativeConstraintPhase = false; // fresh start
  840. pcStr = new ArrayList<Object>(); // start with a blank PC-String
  841. oKay = next.findOrCreate(bodyCopy, starStuffCopy, bindings, badBindings, starBindings, constraints, ktd.kinTerm,
  842. this, pcStr, dyad);
  843. if ((!oKay) && (empties.size() > 0)) {
  844. // Recursive descent or negatedConstraints failed. Empties contains star properties that we are free to change
  845. // in this effort, and might have caused failure to find a conforming value for a UDP. Try 'em all.
  846. // If altering each of those doesn't help, then it's hopeless.
  847. // For each potentially ill-chosen UDP, try to pick a different UDP value for Ego & try again.
  848. String failure;
  849. Literal starLit;
  850. ArrayList<Object> allStars = new ArrayList<Object>(), cumPriorVals = new ArrayList<Object>(), allStarMathVars = new ArrayList<Object>();
  851. TreeMap thisUDMap = (TreeMap) constraints.userDefined.get(egoVar);
  852. MathVariable argForUDPVal;
  853. for (int j = 0; j < starStuff.size(); j++) {
  854. starLit = (Literal) starStuff.get(j);
  855. failure = starLit.predicate.name;
  856. argForUDPVal = (MathVariable) starLit.args.get(0);
  857. if (failure.substring(0, 1).equals("*") && (!allStars.contains(failure))) {
  858. allStars.add(failure);
  859. }
  860. if (failure.substring(0, 1).equals("*") && (!allStarMathVars.contains(argForUDPVal))) {
  861. allStarMathVars.add(argForUDPVal);
  862. }
  863. } // Now allStars is a list of all possible *-props that might have caused failure & allStarMathVars is the associated variables.
  864. Iterator starIter = allStars.iterator();
  865. Object pv = null;
  866. while ((!oKay) && (starIter.hasNext())) {
  867. failure = (String) starIter.next();
  868. if ((thisUDMap != null) && (thisUDMap.get(failure) != null)
  869. && (empties.contains(failure))
  870. && (!(thisUDMap.get(failure) instanceof Constant))) {
  871. // Ego has a constraint on this StarProp, his value was blank before this effort,
  872. // and the argument defining its constraint is not a Constant (ergo, it's a MathVar)
  873. argForUDPVal = (MathVariable) thisUDMap.get(failure);
  874. // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
  875. LiteralAbstract1.failReason = null;
  876. boolean newValFound = true;
  877. cumPriorVals.clear();
  878. udp = (UserDefinedProperty) ego.userDefinedProperties.get(failure);
  879. while ((!oKay) && newValFound) {
  880. bindings.clear();
  881. starBindings.clear();
  882. badBindings.clear();
  883. bindings.put("Ego", ego);
  884. udp.value.clear();
  885. argForUDPVal.updatePriorVals(cumPriorVals);
  886. newValFound = next.newUDPVal(failure, argForUDPVal, "Ego", bindings, starBindings, constraints, this);
  887. if (newValFound) {
  888. if (argForUDPVal.priorValues != null) {
  889. for (int i = 0; i < argForUDPVal.priorValues.size(); i++) {
  890. pv = argForUDPVal.priorValues.get(i);
  891. if (!cumPriorVals.contains(pv)) {
  892. cumPriorVals.add(pv);
  893. }
  894. } // Save the PriorVals for the "experimental variable"
  895. }
  896. for (int i = 0; i < allStarMathVars.size(); i++) { // Erase PriorVals for all other MathVars
  897. Variable var = (Variable) allStarMathVars.get(i);
  898. if (var.priorValues != null) {
  899. var.priorValues.clear();
  900. }
  901. }
  902. argForUDPVal.updatePriorVals(cumPriorVals); // Restore the record for the "experimental variable."
  903. ArrayList<Object> pcStr2 = new ArrayList<Object>(); // start with a blank PC-String
  904. if (next.meetsStarSpecs(ego, egoVar, constraints, starBindings, bindings, "commit", this)) {
  905. oKay = next.findOrCreate(bodyCopy, starStuffCopy, bindings, badBindings, starBindings,
  906. constraints, ktd.kinTerm, this, pcStr2, dyad);
  907. if (oKay) {
  908. pcStr = pcStr2;
  909. }
  910. }

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