/code/LiteralAbstract2.java
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
- import java.util.* ;
- import java.text.* ;
- import java.io.* ;
- /** This abstract class continues the definition of a Literal in Prolog syntax. Literals are the basic building blocks of
- Horn Clauses. They also are the level at which 90% of the action takes place in Example-Generation.
- <p>
- Because so many methods are defined at the Literal level, the code files are broken into 3 classes: LiteralAbstract2, this one,
- and Literal.
- @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
- */
- public abstract class LiteralAbstract2 extends LiteralAbstract1 {
- public static final String stdLitType = "Literal";
- /** Generic zero-arg constructor. Primarily for use in Serialization */
- public LiteralAbstract2() {
- super();
- argType = stdLitType;
- }
- /** Produce the set-difference of list1 minus list2; remove each item in list2 from list1 -- if it's there.
- @param list1 the base list, from which we will subtract.
- @param list2 the list of items to be subtracted.
- @return the set difference.
- */
- public static ArrayList<Object> setDifference(ArrayList<Object> list1, ArrayList<Object> list2) {
- if ((list2 == null) || (list2.isEmpty())) return list1;
- ArrayList<Object> result = new ArrayList<Object>();
- Object obj;
- for (int i=0; i < list1.size(); i++) {
- obj = list1.get(i);
- if (! list2.contains(obj)) result.add(obj);
- }
- return result;
- } // end of method setDifference
- // The following 21 methods are all related to generating example-persons who illustrate the kinship
- // definition contained in the enclosing clauseBody. They all FindOrCreate_X, i.e. they find a single
- // existing person to use, or create one if no suitable person can be re-used.
- // This is in contrast to the set of methods which follows, the FindAll_X methods, which only label existing persons.
- boolean findOrCreate(ArrayList<Object> cbody, ArrayList<Object> starStuff, TreeMap bindings, TreeMap badBindings, ArrayList<Object> starBindings,
- ConstraintObj constraints, String kinTerm, ClauseBody cb, ArrayList<Object> pcStr, Dyad dyad)
- throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
- int kidFlag = 0, parFlag = 0, mateFlag = 0; // signals re: past failures
- // Find the correct method for this Primitive Predicate & call it.
- // if (Context.breakFlag) Context.breakpoint();
- if (predicate.name.equals("parent"))
- return findOrCreateBirthLink("?", "?", 0, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
- if (predicate.name.equals("child"))
- return findOrCreateBirthLink("?", "?", 1, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
- if (predicate.name.equals("father"))
- return findOrCreateBirthLink("M", "?", 0, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
- if (predicate.name.equals("mother"))
- return findOrCreateBirthLink("F", "?", 0, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
- if (predicate.name.equals("son"))
- return findOrCreateBirthLink("?", "M", 1, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
- if (predicate.name.equals("daughter"))
- return findOrCreateBirthLink("?", "F", 1, cbody, starStuff, bindings, badBindings, starBindings, constraints, kidFlag, parFlag, false, kinTerm, cb, pcStr, dyad);
- if ((predicate.name.equals("husband")) || (predicate.name.equals("wife"))
- || (predicate.name.equals("spouse")))
- return findOrCreateSpouse(cbody, starStuff, bindings, badBindings, starBindings, false, constraints, mateFlag, false, kinTerm, cb, pcStr, dyad);
- if ((predicate.name.equals("divorced")) && (args.size() == 2))
- return findOrCreateSpouse(cbody, starStuff, bindings, badBindings, starBindings, true, constraints, mateFlag, false, kinTerm, cb, pcStr, dyad);
- if (predicate.name.substring(0, 1).equals("*"))
- return findOrCreateStarLink(cbody, starStuff, bindings, badBindings, starBindings, constraints, 0, false, kinTerm, cb, pcStr, dyad);
- if ((predicate.name.equals("not")) || (predicate.category instanceof MathCategory))
- return findOrCreateMathLink(cbody, starStuff, bindings, badBindings, starBindings, constraints, false, kinTerm, cb, pcStr, dyad);
- throw new KSInternalErrorException("Non-Primitive Predicate Encountered in Literal.findOrCreate.\nLiteral is: " + this);
- } // end of dispatch method findOrCreate
- boolean findOrCreateBirthLink(String parSex, String kidSex, int parArg, ArrayList<Object> remLits, ArrayList<Object> starStuff, TreeMap bindings,
- TreeMap badBindings, ArrayList<Object> starBindings, ConstraintObj constraints, int kidFlag, int parFlag,
- boolean keepBB, String kinTerm, ClauseBody cb, ArrayList<Object> pcStr, Dyad dyad)
- throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
- // This handles parent, father, mother, son, & daughter predicates via the 1st 3 parameters.
- // For each arg, either (1) a suitable Individual already exists in the Indiv-Census
- // so we find it and bind it, then recurse on remLits. OR
- // (2) we create a suitable Individual and add it to the bindings - honoring constraints - then recurse.
- // badBindings is a TreeMap of variables (argNames) & lists of prohibited bindings (individuals)
- int kidArg, resetInd = Context.current.indSerNumGen, resetFam = Context.current.famSerNumGen;
- int sbSize = starBindings.size();
- kidArg = (parArg + 1) % 2;
- Variable parent = (Variable)args.get(parArg), child = (Variable)args.get(kidArg);
- Individual parentIndiv = (Individual)bindings.get(parent.argName), childIndiv = (Individual)bindings.get(child.argName);
- String bindingMade = null, parentSex = parSex;
- // if (Context.breakFlag) System.out.println("F/C_BirthLink on " + this);
- Argument argBound = null;
- ArrayList<Object> parentSexList;
- if (parSex.equals("?")) {
- parentSexList = resolveOppo(bindings, constraints, parent);
- if (parentSexList == null) parentSex = "?";
- else if (parentSexList.contains("F")) parentSex = "F";
- else if (parentSexList.contains("M")) parentSex = "M";
- }
- Family fam = null;
- if (LiteralAbstract1.negativeConstraintPhase) {
- // One or both of these may have been bound earlier in a 'positive' phase, and carried (via bindings
- // list) into a 'negatedConstraintsSatisfied' phase. So double check constraints. Use the _Strictly_
- // versions,'cuz we don't want to change anything on a bound arg/object pair.
- if ((childIndiv != null) && (! childIndiv.meetsConstraintsStrictly(child, constraints, bindings, starBindings)))
- return false;
- if ((parentIndiv != null) && (! parentIndiv.meetsConstraintsStrictly(parent, constraints, bindings, starBindings)))
- return false;
- } // end of if-negativeConstraintPhase
- // we know that either parent or child (maybe both) already exists
- if ((parentIndiv != null) && (childIndiv == null)) { // parent already exists; look for child of right sex
- Individual existingKid;
- ArrayList<Object> badKids = (ArrayList<Object>)badBindings.get(child.argName); // list of individuals we can NOT accept
- if (badKids == null) badKids = new ArrayList<Object>();
- existingKid = kidSearch(parentIndiv, kidSex, child, constraints, bindings, badKids, starBindings, cb);
- if (existingKid == null) { // no match found among existing kids
- ArrayList<Object> kidSexList;
- if (kidSex.equals("?")) {
- kidSexList = resolveOppo(bindings, constraints, child);
- if (kidSexList == null) kidSex = "?";
- else if (kidSexList.contains("F")) kidSex = "F";
- else if (kidSexList.contains("M")) kidSex = "M";
- }
- // kidFlag = 0 means we've never created a kid for this variable
- // kidFlag = 1-2 means we created a kid in family#0 previously (M & F) & it didn't work
- // kidFlag = 3-4 means we've used or created a 2nd marriage & new kid - still didn't work
- // kidFlag = 5-6 means we've created a new marriage & new kid - nothing works
- if (kidFlag == 0) fam = findOrMakeMarriage(parentIndiv, 0, parent.argName, constraints);
- else if (kidFlag <= 2) // try 2nd marriage
- fam = findOrMakeMarriage(parentIndiv, 1, parent.argName, constraints);
- else if (kidFlag <= 4) // force a new marriage
- fam = findOrMakeMarriage(parentIndiv, 99, parent.argName, constraints);
- else if (kidFlag >= 5) return false; // nothing left to try
- kidFlag++;
- BoolFlag failFlag = new BoolFlag(false);
- childIndiv = new Individual("*&^%$", kidSex, fam, null, child.argName, null, bindings,
- starBindings, constraints, child, failFlag, cb);
- if (failFlag.value) {
- LiteralAbstract1.failReason = failFlag.reason;
- return false;
- } // end of failFlag===true
- if ((fam != null) && (fam.getMarriageDate().length() < 4)) fam.generateMarriageDate();
- } // end of if-no-suitable-existingKid-found
- else childIndiv = existingKid;
- bindings.put(child.argName, childIndiv);
- if (childIndiv.node == null) childIndiv.node = new Node();
- else childIndiv.node.appearances++;
- bindingMade = child.argName;
- if (dyad != null) dyad.path.add(childIndiv);
- argBound = child;
- cb.pcCounter++;
- addToPCString(pcStr, parentIndiv, childIndiv, false);
- child.treeLevel = parent.treeLevel - 1;
- if (bindingMade.equals("Alter")) {
- cb.level = child.treeLevel;
- if (dyad != null) dyad.alter = childIndiv;
- }
- } // end of if-parent-already-exists
- else if ((parentIndiv == null) && (childIndiv != null)) { // kid already exists, parent doesn't
- BoolFlag failFlag = new BoolFlag(false);
- fam = findOrMakeBirthFamily(childIndiv, parentSex, parent.argName, null, bindings,
- starBindings, constraints, parent, failFlag, cb);
- if (failFlag.value) {
- LiteralAbstract1.failReason = failFlag.reason;
- return false;
- } // end of failFlag===true
- ArrayList<Object> badParents = (ArrayList<Object>)badBindings.get(parent.argName);
- if (badParents == null) badParents = new ArrayList<Object>();
- parentIndiv = parentSearch(fam, parentSex, parent, constraints, bindings, badParents, parFlag, starBindings, cb);
- if (parentIndiv == null) return false;
- if ((fam != null) && (fam.getMarriageDate().length() < 4)) fam.generateMarriageDate();
- bindings.put(parent.argName, parentIndiv);
- if (parentIndiv.node == null) parentIndiv.node = new Node();
- else parentIndiv.node.appearances++;
- bindingMade = parent.argName;
- if (dyad != null) dyad.path.add(parentIndiv);
- argBound = parent;
- cb.pcCounter++;
- addToPCString(pcStr, childIndiv, parentIndiv, true);
- parent.treeLevel = child.treeLevel + 1;
- if (bindingMade.equals("Alter")) {
- cb.level = parent.treeLevel;
- if (dyad != null) dyad.path.add(parentIndiv);
- }
- } // end of else-if-kid-already-exists
- else { // both already exist & bound; verify they are recorded as parent/child & meet constraints
- // 'cuz both are already bound, there's no point in ever repeating this level -- max both flags
- kidFlag = 6;
- parFlag = 2;
- if ((childIndiv.birthFamily == null) && (parentIndiv.marriages.isEmpty())) {
- fam = new Family(parentIndiv, parent.argName, constraints.divorce);
- fam.addChild(childIndiv);
- } // end of if-birthFamily-not-created-and-parent-unmarried
- else if (childIndiv.birthFamily == null) { // parent has an existing marriage
- fam = (Family)parentIndiv.marriages.get(0);
- fam.addChild(childIndiv);
- } // end of birthFamily-not-created-but-parent-married
- else if ((childIndiv.birthFamily != null) && (parentIndiv.marriages.isEmpty())) {
- // BirthFam may have a dummy-parent in it that parent can replace
- fam = childIndiv.birthFamily;
- if (! (childIndiv.birthFamily.subForDummyParent(parentIndiv))) // not-compatible
- return false;
- } // end of if-birthFamily-created-and-parent-unmarried
- else { // birthFam-exists-and-parent-already-married. Our only hope is that they are compatible.
- fam = childIndiv.birthFamily;
- if (! (parentIndiv.marriages.contains(childIndiv.birthFamily))) // if compatible, do nothing
- return false;
- } // end of birthFam-exists-and-parent-already-married
- fam.checkFamDOBs();
- if ((fam != null) && (fam.getMarriageDate().length() < 4)) fam.generateMarriageDate();
- cb.pcCounter++; // even though no one was bound, we have successfully traversed a link
- // Since neither arg was 'pre-Bound' we'll emit a PC-String in same form as this
- if (predicate.name.equals("father") || predicate.name.equals("mother") || predicate.name.equals("parent"))
- addToPCString(pcStr, childIndiv, parentIndiv, true);
- else addToPCString(pcStr, parentIndiv, childIndiv, false);
- } // end of else-they-both-already-exist
- // If we get this far, we have not (yet) failed (returned false).
- // If we can successfully recurse on remaining literals, we succeed (return true).
- // If not, then we must call this method again with badBindings & the updated flags
- Literal next = null;
- ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
- while ((next == null) && ((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)))
- next = cb.pop(remLitsCopy, starStuffCopy, bindings, kinTerm); // pop returns the next processable literal
- if (next == null) { // at end of clause body. Check clause-level constraints.
- if (negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb))
- return true;
- } // end of at-end-of-clauseBody
- else if (next.findOrCreate(remLitsCopy, starStuffCopy, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
- return true;
- // Recursive descent or negatedConstraints failed. LiteralAbstract1.failReason tells us if failure to
- // find a conforming value for a UDP is the cause. If not, then it's 'regular' causes.
- // If the cause is a UDP, then try to pick a different UDP value & try again with current bindings.
- // If not, then retract current binding & try again.
- // if (Context.breakFlag) System.out.println("F/C_BirthLink FAILS on " + this);
- if ((LiteralAbstract1.failReason != null) && (bindingMade != null)) {
- Variable whoVar = child; // bindingMade has to be one of them
- if (parent.argName.equals(bindingMade)) whoVar = parent;
- TreeMap thisUDMap = (TreeMap)constraints.userDefined.get(whoVar);
- String failure = LiteralAbstract1.failReason;
- if ((thisUDMap != null) && (thisUDMap.get(failure) != null) &&
- (! (thisUDMap.get(failure) instanceof Constant))) {
- // it was a StarProp failure, and this arg has a constraint on that StarProp,
- // and the argument defining its constraint is not a Constant (ergo, it's a MathVar or a Variable for a person)
- if (thisUDMap.get(failure) instanceof MathVariable) {
- MathVariable argForUDPVal = (MathVariable)thisUDMap.get(failure);
- // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
- LiteralAbstract1.failReason = null;
- while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
- if (((next != null) &&
- next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
- || ((next == null) &&
- negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
- return true;
- } // end of while-loop. In this loop, newUDPVal tries to find a new conforming value
- // for this UDP. If it succeeds, then it calls find/create (or negatedConstraints)
- // in an attempt to complete the generation of this example. If that succeeds,
- // it returns true; if that fails, it picks another and tries again. If all possible UDP values
- // are used up without success, the loop ends and we go on.
- } // end of it-was-a-MathVariable
- else { // it-must-be-a-Variabe-for-a-person
- Variable argForUDPVal = (Variable)thisUDMap.get(failure);
- // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
- LiteralAbstract1.failReason = null;
- while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
- if (((next != null) &&
- next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
- || ((next == null) &&
- negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
- return true;
- } // end of while-loop.
- } // end of it-must-be-a-Variabe-for-a-person
- } // end of there is a UDP constraint for this bound-arg
- } // end of failed-due-to-a-UDP-value
- if (pcStr.size() >= 1) pcStr.remove(pcStr.size() -1); // retract the PC-String addition
- if (dyad != null && dyad.path.size() > 0) dyad.path.remove(dyad.path.size() -1);
- if (bindingMade != null) cb.pcCounter--; // if we incremented a counter, un-do that.
- // retract any binding made - put it on BadBindings list; retract property bindings made here.
- updateBindingsEtc(bindings, badBindings, bindingMade, argBound, starBindings, sbSize);
- if ((kidFlag < 6) && (parFlag < 2)) {
- if (findOrCreateBirthLink(parSex, kidSex, parArg, remLits, starStuff, bindings, badBindings,
- starBindings, constraints, kidFlag, parFlag, true, kinTerm, cb, pcStr, dyad))
- return true;
- // if we get this far, all binding attempts have failed. Pass failure up to next higher level.
- // keepBB determines whether we retain our record of a badBinding at this level.
- // If we're about to send a FAIL back to a higher-level literal in the chain, we want to
- // erase them. But if we're FAILing back to an earlier iteration at this level, keep them.
- // In EITHER case, make sure any property bindings have been undone.
- updateBindingsEtc(bindings, badBindings, null, null, starBindings, sbSize);
- }
- if (! keepBB) {
- badBindingsRemove(bindingMade, argBound, badBindings);
- Context.current.resetTo(resetInd, resetFam);
- } // end of don't-keep-badBindings
- return false;
- // end of recursive-descent-or-negatedConstraints-failed
- } // end of method findOrCreateBirthLink
- ArrayList<Object> resolveOppo(TreeMap bindings, ConstraintObj constraints, Variable argVar) throws KSConstraintInconsistency {
- // If there are no gender constraints on the variable argVar, there's nothing to resolve.
- // If the gender constraints contain either M or F, there's nothing to resolve.
- // If they contain any "Opposite of" or "Same as" constraints, chase & resolve if possible
- ArrayList<Object> answer = (ArrayList<Object>)constraints.gender.get(argVar.argName), otherConstrLst;
- if (answer == null) return answer;
- boolean male = false, female = false;
- ArrayList<Object> oppo = new ArrayList<Object>(), same = new ArrayList<Object>();
- String constraint, sameSexVarName, oppoSexVarName;
- Individual sameSexInd, oppoSexInd;
- for (int i=0; i < answer.size(); i++) {
- constraint = (String)answer.get(i);
- if (constraint.equals("F")) female = true;
- else if (constraint.equals("M")) male = true;
- else if (constraint.indexOf("Opposite") > -1) oppo.add(constraint.substring(12));
- else if (constraint.indexOf("Same") > -1) same.add(constraint.substring(8));
- } // end of for-i=each-constraint
- if (male && female) throw new KSConstraintInconsistency("for " + argVar);
- if (male || female) return answer;
- if (! same.isEmpty()) {
- for (int j=0; j < same.size(); j++) {
- sameSexVarName = (String)same.get(j);
- sameSexInd = (Individual)bindings.get(sameSexVarName);
- if (sameSexInd != null) {
- if (sameSexInd.gender.equals("F")) female = true;
- else if (sameSexInd.gender.equals("M")) male = true; }
- else {
- otherConstrLst = (ArrayList<Object>)constraints.gender.get(sameSexVarName);
- if (otherConstrLst.contains("F")) female = true;
- else if (otherConstrLst.contains("M")) male = true;
- } // end of else-sameSexVarName-not-bound-yet
- } // end of for-j=each-same-sex-variable-name
- } // end of same-is-not-empty
- if (! oppo.isEmpty()) {
- for (int j=0; j < oppo.size(); j++) {
- oppoSexVarName = (String)oppo.get(j);
- oppoSexInd = (Individual)bindings.get(oppoSexVarName);
- if (oppoSexInd != null) {
- if (oppoSexInd.gender.equals("F")) male = true;
- else if (oppoSexInd.gender.equals("M")) female = true; }
- else {
- otherConstrLst = (ArrayList<Object>)constraints.gender.get(oppoSexVarName);
- if (otherConstrLst.contains("M")) female = true;
- else if (otherConstrLst.contains("F")) male = true;
- } // end of else-oppoSexVarName-not-bound-yet
- } // end of for-j=each-oppo-sex-variable-name
- } // end of oppo-is-not-empty
- if (male && female) throw new KSConstraintInconsistency("Both M & F required for " + argVar);
- if (male) {
- answer = new ArrayList<Object>();
- answer.add("M");
- } // end of if-male
- if (female) {
- answer = new ArrayList<Object>();
- answer.add("F");
- } // end of if-female
- return answer;
- } // end of method resolveOppo
- public boolean newUDPVal(String failedProp, Variable theVar, String bindingMade, TreeMap bindings,
- ArrayList<Object> starBindings, ConstraintObj constraints, ClauseBody cb)
- throws KSInternalErrorException, KSBadHornClauseException, ClassNotFoundException, KSConstraintInconsistency {
- // Existing value for person's StarProp did not work out. Return true if a different conforming
- // value can be assigned.
- Individual ind = (Individual)bindings.get(bindingMade);
- UserDefinedProperty udp = (UserDefinedProperty)ind.userDefinedProperties.get(failedProp);
- if (udp == null) throw new KSInternalErrorException("Null UDP in Literal.newUDPVal for " + bindingMade);
- theVar.updatePriorVals(theVar.getVal());
- // Remove the old values, but retain the record of this value as a priorValue
- theVar.clearVal();
- Iterator iter = starBindings.iterator();
- while (iter.hasNext()) {
- StarPropertyBinding spb = (StarPropertyBinding)iter.next();
- if ((spb.personBound == ind) && (spb.starPropName.equals(failedProp)))
- iter.remove();
- } // end of loop thru starBindings
- return ind.findConformingValue(failedProp, (Argument)theVar, starBindings, bindings, constraints, "commit", cb);
- } // end of method newUDPVal
- void badBindingsRemove(String bindingMade, Argument argBound, TreeMap badBindings) {
- if (bindingMade == null) return;
- badBindings.remove(bindingMade);
- if (argBound instanceof Variable) ((Variable)argBound).priorValues = null;
- } // end of method badBindingsRemove()
- boolean negatedConstraintsSatisfied(ArrayList<Object> starStuff, TreeMap bindings, TreeMap badBindings, ArrayList<Object> starBindings,
- ConstraintObj constraints, String kinTerm, ClauseBody cb)
- throws KSInternalErrorException, KSBadHornClauseException, ClassNotFoundException {
- // Check to see if any of the ClauseBodies in the Negated Constraint are true. If any one
- // of them is true, the test is failed and we return false.
- // if (Context.breakFlag) Context.breakpoint();
- if ((constraints.negated == null) || (constraints.negated.isEmpty())) return true;
- Individual ego = (Individual)bindings.get("Ego");
- ClauseBody cbNeg;
- ArrayList<Object> bodyCopy;
- TreeMap bindingsCopy = new TreeMap(bindings);
- ConstraintObj constraintsCopy;
- for (int i=0; i < constraints.negated.size(); i++) {
- cbNeg = (ClauseBody)constraints.negated.get(i);
- constraintsCopy = new ConstraintObj(constraints);
- constraintsCopy.negated = new ArrayList<Object>(); // to prevent infinite recursion
- // Any restrictions on variables induced by a negated clause should apply only to a
- // "deep copy" of the args found in the main clausebody, not the main args themselves.
- bodyCopy = new ArrayList<Object>();
- for (int k=0; k < cbNeg.body.size(); k++)
- bodyCopy.add(((Literal)cbNeg.body.get(k)).copy());
- // Keep all current constraints except the negated ones, and add any new constraints
- // (including negated ones) appearing in cbNeg.
- try {
- for (int j=0; j < bodyCopy.size(); j++)
- if (! (((Literal)bodyCopy.get(j)).constraintCheck(ego.gender, constraintsCopy, new ArrayList<Object>(), starStuff)))
- throw new KSConstraintInconsistency(" ");
- LiteralAbstract1.negativeConstraintPhase = true;
- if (! LiteralAbstract1.finalConstraintCheck(ego.gender, bindingsCopy, constraintsCopy, bodyCopy, new ArrayList<Object>(), starStuff))
- throw new KSConstraintInconsistency(" ");
- LiteralAbstract1.negativeConstraintPhase = false;
- // finalConstraintCheck does post-processing & a final conflict-check; the negConstraints flag influences its logic
- Literal next = null;
- while (((bodyCopy.size() > 0) || (starStuff.size() > 0)) && (next == null))
- next = cb.pop(bodyCopy, starStuff, bindingsCopy, kinTerm); // next = first non-constraint literal in body
- if (next == null)
- throw new KSBadHornClauseException("No processable literals in negated clause:/n not(" + cbNeg.body + ")");
- else if (constraintsCopy.allowCreation) {
- LiteralAbstract1.negativeConstraintPhase = true;
- if (next.findOrCreate(bodyCopy, starStuff, bindingsCopy, badBindings, starBindings, constraintsCopy, kinTerm, cb, new ArrayList<Object>(), null)) {
- // We don't keep the PC-String from a negated Constraint, so we pass a throw-away empty list
- LiteralAbstract1.negativeConstraintPhase = false;
- return false;
- }else LiteralAbstract1.negativeConstraintPhase = false;
- } // end of if-creation-is-allowed
- else if (next.fillInNames_bool(kinTerm, bodyCopy, starStuff, cbNeg, bindingsCopy, constraintsCopy, null, new ArrayList<Object>()))
- return false;
- } catch (KSConstraintInconsistency e) { }
- // If a ConstraintInconsistency occurs here, it means the constraints alone are enough to
- // make this ClauseBody impossible. So treat this the same as a failure by findOrCreate;
- // go on to the next clauseBody (if any).
- } // end of for-i=each-negated-constraint
- return true;
- } // end of method negatedConstraintsSatisfied
- void updateBindingsEtc(TreeMap bindings, TreeMap badBindings, String bindingMade, Argument argBound,
- ArrayList<Object> starBindings, int sbSize) {
- // This method is invoked when backtracking is about to occur. We must retract the current bindingMade,
- // & add it to badBindings. Any property bindings made in this round are un-done.
- StarPropertyBinding spb;
- UserDefinedProperty udp;
- // First Process StarBindings. 'Normal' SPBs reflect a linking and binding event.
- // But SPBs w/ PersonBound == null reflect addition of a value via assureContainedBy
- for (int i = starBindings.size() - 1; i >= sbSize; i--) {
- spb = (StarPropertyBinding)starBindings.get(i);
- if (spb.mathVarBound != null) {
- for (int j=0; j < spb.valsAssigned.size(); j++)
- spb.mathVarBound.removeVal(spb.valsAssigned.get(j));
- if (spb.personBound != null) // Person's UDP & MathVar were linked
- spb.mathVarBound.unLink();
- }else if (spb.variableBound != null) {
- for (int j=0; j < spb.valsAssigned.size(); j++)
- spb.variableBound.removeVal(spb.valsAssigned.get(j));
- if (spb.personBound != null) {
- udp = (UserDefinedProperty)spb.personBound.userDefinedProperties.get(spb.starPropName);
- udp.value = setDifference(udp.value, spb.valsAssigned);
- } // end of an-Individual's-property-was-bound
- } // end of it's-a-Variable
- starBindings.remove(i);
- } // end of loop thru starBindings
- // Next Process BadBindings.
- if (bindingMade != null) {
- ArrayList<Object> badList = (ArrayList<Object>)badBindings.get(bindingMade);
- if (badList == null) badList = new ArrayList<Object>();
- Object bMade = bindings.get(bindingMade); // a MathVar is bound to its values list
- if (bMade instanceof ArrayList) badList.addAll((ArrayList<Object>)bMade);
- else badList.add(bMade);
- if (bMade instanceof Individual) {
- if (((Individual)bMade).node.appearances > 1) ((Individual)bMade).node.appearances--;
- else ((Individual)bMade).node = null;
- }
- badBindings.put(bindingMade, badList);
- bindings.remove(bindingMade);
- // We unLink a MathVar if it is removed from Bindings
- // if (argBound instanceof MathVariable) ((MathVariable)argBound).unLink();
- // REMOVED ON THEORY THAT SPBs WILL MANAGE UN-LINKING
- }
- } // end of method updateBindingsEtc
- public void addToPCString(ArrayList<Object> pcStr, Individual preBound, Individual newBound, boolean preIsKid) {
- // Create a standardized literal expressing the BirthLink relationship of newBound to preBound.
- // NewBound should be arg0 of that literal, and preBound should be arg1.
- String preBoundTag = "#" + preBound.serialNmbr, newBoundTag = "#" + newBound.serialNmbr,
- pc, newBoundSex = newBound.gender;
- if (preIsKid) { // must create a parental pc
- if (newBoundSex.equals("M")) pc = "Fa";
- else if (newBoundSex.equals("F")) pc = "Mo";
- else pc = "P";
- }else { // Must create a child pc
- if (newBoundSex.equals("M")) pc = "So";
- else if (newBoundSex.equals("F")) pc = "Da";
- else pc = "C"; }
- pcStr.add(pc + "(" + newBoundTag + "," + preBoundTag + ")");
- } // end of method addToPCString for BirthLinks
- public void addToPCString(ArrayList<Object> pcStr, boolean divReq, Individual preBound, Individual newBound) {
- // Create a standardized literal expressing the SpouseLink relationship of newBound to preBound.
- // NewBound should be arg0 of that literal, and preBound should be arg1.
- String preBoundTag = "#" + preBound.serialNmbr, newBoundTag = "#" + newBound.serialNmbr,
- pc, newBoundSex = newBound.gender;
- if (newBoundSex.equals("M")) pc = "Hu";
- else if (newBoundSex.equals("F")) pc = "Wi";
- else pc = "Sp";
- pcStr.add(pc + "(" + newBoundTag + "," + preBoundTag + ")");
- } // end of method addToPCString for SpouseLink
- boolean findOrCreateStarLink(ArrayList<Object> remLits, ArrayList<Object> starStuff, TreeMap bindings, TreeMap badBindings, ArrayList<Object> starBindings,
- ConstraintObj constraints, int tryFlag, boolean keepBB, String kinTerm, ClauseBody cb, ArrayList<Object> pcStr, Dyad dyad)
- throws KSBadHornClauseException, KSInternalErrorException, KSConstraintInconsistency, ClassNotFoundException {
- // The current literal is a *-predicate declaring a value (via a constant or variable) for a person's UDP.
- // Arg0 is the value (a Variable/MathVariable/Constant); Arg1 is the Variable for the person whose UDP's value must equal arg0.
- // *-predicates can serve as constraints, or can define a trait that "links" 2 individuals in the chain from Ego to Alter.
- // Only the latter case is handled here; constraints were handled earlier in cb.constraintCheck.
- // NOTE: The semantics of a *-predicate are simplistic. The literal "*friends(X, Gary)" means that the MathVariable X has a
- // value exactly equal to the value of Gary's UserDefinedProperty *friends. Sub-sets and super-sets are not considered equal.
- // The math operator "contains" expresses sub-set relationships, if desired.
- int resetInd = Context.current.indSerNumGen, resetFam = Context.current.famSerNumGen, sbSize = starBindings.size();
- String bindingMade = null;
- MathVariable mathVar = null;
- Constant konstant = null;
- Variable personVar = (Variable)args.get(1), valPerVar = null;
- Individual person = (Individual)bindings.get(personVar.argName), valPer = null; // null = that variable not yet bound
- // if (Context.breakFlag) Context.breakpoint();
- // arg0 is either a MathVariable, a Variable, or a Constant.
- UserDefinedProperty udp;
- Argument arg0 = (Argument)args.get(0), argBound = null;
- if (arg0 instanceof MathVariable) mathVar = (MathVariable)arg0;
- else if (arg0 instanceof Constant) konstant = (Constant)arg0;
- else { // must be a Variable
- valPerVar = (Variable)arg0;
- valPer = (Individual)bindings.get(valPerVar.argName); // may be null if this Variable not yet bound
- }
- if (LiteralAbstract1.negativeConstraintPhase) {
- // Person and valPer may have been bound earlier in a 'positive' phase, and carried (via bindings
- // list) into a 'negatedConstraintsSatisfied' phase. So double check constraints. Use the _Strictly_
- // versions,'cuz we don't want to change anything on a bound arg/object pair.
- if ((person != null) && (! person.meetsConstraintsStrictly(personVar, constraints, bindings, starBindings)))
- return false;
- if ((valPer != null) && (! valPer.meetsConstraintsStrictly(valPerVar, constraints, bindings, starBindings)))
- return false;
- } // end of if-negativeConstraintPhase
- if ((person != null) && ((mathVar != null) || (konstant != null))) {
- // person-is-bound-and-arg0-is-a-mathVar-or-constant
- udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
- if ((udp.value.size() > 1) && (udp.singleValue)) // invalid condition: Panic!
- throw new KSInternalErrorException("In findOrCreateStarLink: encountered single-valued UDP with multiple values");
- // findConformingValue will transfer person's value(s) to the mathVar's value(s) if person has any and they
- // 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,
- // then it will invent a conforming value. If no conforming value is possible, it returns 'false', otherwise 'true.'
- if (! person.findConformingValue(predicate.name, arg0, starBindings, bindings, constraints, "commit", cb)) {
- LiteralAbstract1.failReason = predicate.name;
- return false;
- } // end of failed to find a conforming value.
- // Found a conforming value. Done.
- bindingMade = arg0.argName;
- if (dyad != null) dyad.path.add(person);
- if (person.node == null) person.node = new Node();
- else person.node.appearances++;
- argBound = arg0;
- person.yoke(mathVar, null, konstant, null, udp, bindingMade, bindings, starBindings);
- } // end of person-is-bound-and-arg0-is-a-mathVar-or-constant
- else if ((person != null) && (valPerVar != null)) {
- // person-is-bound-and-value-is-also-a-person
- udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
- if (valPer != null) { } // Do nothing. We validity-checked both of them above & all is OK.
- else if (! udp.typ.equals("individual"))
- throw new KSInternalErrorException("In findOrCreateStarLink: Personal variable '" + valPerVar + "' used for UDP of type " + udp.typ);
- else if (! person.findConformingValue(predicate.name, arg0, starBindings, bindings, constraints, "commit", cb)) {
- LiteralAbstract1.failReason = predicate.name;
- return false;
- } // end of failed to find a conforming value.
- // Found a conforming value. Done.
- bindingMade = valPerVar.argName; // We bind valPerVar to the person who conforms.
- if (dyad != null) dyad.path.add(valPer);
- argBound = valPerVar;
- if (valPer.node == null) valPer.node = new Node();
- else valPer.node.appearances++;
- bindings.put(valPerVar.argName, valPer); // Binding it extends the chain of relations
- } // end of person-is-bound-and-value-is-also-a-person
- else if ((person == null) && ((mathVar != null) || (konstant != null))) {
- // Person-is-unbound-and-mathVar-or-constant-is-bound. Call a Context instance method to find a person who has a value equal to
- // the mathVar/Constant's value, if any. If none is found, create one and give him this (or a conforming) value.
- person = Context.current.findConformingPerson(arg0, predicate.name, personVar, constraints, badBindings,
- starBindings, bindings); // null -> found none
- if (person != null) createPersonalStarLink(person, predicate.name, starBindings);
- else {
- String indNam = "Hypothetical Person", gender = "?", birthdate = "Jan 1, 1970"; // neuter gender forces constructor to search constraints
- BoolFlag failFlag = new BoolFlag(false);
- person = new Individual(indNam, gender, null, birthdate, ((Argument)args.get(1)).argName, null, bindings,
- starBindings, constraints, personVar, failFlag, cb);
- if (failFlag.value) {
- LiteralAbstract1.failReason = failFlag.reason;
- return false;
- }else createPersonalStarLink(person, predicate.name, starBindings);
- }
- // If we're here, an appropriate person was found
- bindingMade = personVar.argName; // We bind personVar to the conforming person who can take on this UDP value.
- if (dyad != null) dyad.path.add(person);
- argBound = personVar;
- udp = (UserDefinedProperty)person.userDefinedProperties.get(predicate.name);
- if (person.node == null) person.node = new Node();
- else person.node.appearances++;
- person.yoke(mathVar, null, konstant, personVar, udp, bindingMade, bindings, starBindings);
- } // end of Person-is-unbound-and-mathVar-or-constant-is-bound
- else if ((person == null) && (valPer != null)) {
- // person-is-unbound-and-valPerVar-is-bound. Call a Context instance method to find a person who has this value.
- // If none is found, create one and give him this value.
- person = Context.current.findConformingPerson(valPer, predicate.name, personVar, constraints, badBindings,
- starBindings, bindings); // null -> found none
- if (person == null) {
- String indNam = "Hypothetical Person", gender = "?", birthdate = "Jan 1, 1970";
- BoolFlag failFlag = new BoolFlag(false);
- person = new Individual(indNam, gender, null, birthdate, personVar.argName, null, bindings,
- starBindings, constraints, personVar, failFlag, cb);
- if (failFlag.value) {
- LiteralAbstract1.failReason = failFlag.reason;
- return false;
- }
- }
- // If we're here, an appropriate person was found
- bindingMade = personVar.argName; // We bind personVar to the conforming person who can take on this UDP value.
- if (dyad != null) dyad.path.add(person);
- bindings.put(personVar.argName, person); // Binding it extends the chain of relations
- if (person.node == null) person.node = new Node();
- else person.node.appearances++;
- argBound = personVar;
- } // end of person-is-unbound-and-valPerVar-is-bound
- else throw new KSInternalErrorException("findOrCreateStarLink found no value to assign."); // should never get here
- // OK. We've traversed a starLink successfully. Return or recurse.
- cb.starCounter++;
- // Now emit a PC-String like '*(<value>, <Person.serial#>)'
- String perSerial = "#" + person.serialNmbr, arg0Str;
- if (valPer != null) arg0Str = "#" + valPer.serialNmbr; // a Variable for a person is bound to the Individual
- else arg0Str = "value=" + ((ArrayList<Object>)bindings.get(arg0.argName)).get(0).toString();
- pcStr.add("*(" + arg0Str + "," + perSerial + ")");
- Literal next = null;
- ArrayList<Object> remLitsCopy = new ArrayList<Object>(remLits), starStuffCopy = new ArrayList<Object>(starStuff);
- while ((next == null) && ((remLitsCopy.size() > 0) || (starStuffCopy.size() > 0)))
- next = cb.pop(remLitsCopy, starStuffCopy, bindings, kinTerm); // pop returns the next processable literal
- if (next == null) { // at end of clause body. Check clause-level constraints.
- if (negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb))
- return true;
- } // end of at-end-of-clauseBody
- else if (next.findOrCreate(remLitsCopy, starStuffCopy, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
- return true;
- // Recursive descent or negatedConstraints failed. LiteralAbstract1.failReason tells us if failure to
- // find a conforming value for a person's UDP is the cause. If not, then it's 'regular' causes.
- // The failure can only involve a person in this literal if we bound either personVar or valPerVar.
- // If the cause is a UDP for one of those, then try to pick a different UDP value & try again with current bindings.
- // If not, then retract current binding & try again.
- // if (Context.breakFlag) System.out.println("F/C_StarLink FAILS on " + this);
- if ((LiteralAbstract1.failReason != null) && (bindingMade != null) &&
- (bindingMade.equals(personVar.argName) || ((valPerVar != null) && bindingMade.equals(valPerVar.argName)))) {
- String failure = LiteralAbstract1.failReason;
- Variable whoVar = personVar; // bindingMade has to be one of them
- if ((valPerVar != null) && bindingMade.equals(valPerVar.argName)) whoVar = valPerVar;
- TreeMap thisUDMap = (TreeMap)constraints.userDefined.get(whoVar);
- if ((thisUDMap != null) && (thisUDMap.get(failure) != null) &&
- (! (thisUDMap.get(failure) instanceof Constant))) {
- // it was a StarProp failure, and this arg has a constraint on that StarProp,
- // and the argument defining its constraint is not a Constant (ergo, it's a MathVar or a Variable for a person)
- if (thisUDMap.get(failure) instanceof MathVariable) {
- MathVariable argForUDPVal = (MathVariable)thisUDMap.get(failure);
- // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
- LiteralAbstract1.failReason = null;
- while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
- if (((next != null) &&
- next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
- || ((next == null) &&
- negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
- return true;
- } // end of while-loop. In this loop, newUDPVal tries to find a new conforming value
- // for this UDP. If it succeeds, then it calls find/create (or negatedConstraints)
- // in an attempt to complete the generation of this example. If that succeeds,
- // it returns true; if that fails, it picks another and tries again. If all possible UDP values
- // are used up without success, the loop ends and we go on.
- } // end of it-was-a-MathVariable
- else { // it-must-be-a-Variabe-for-a-person
- Variable argForUDPVal = (Variable)thisUDMap.get(failure);
- // If we can try again with a different value for UDP, do it. If not, fall thru to failure.
- LiteralAbstract1.failReason = null;
- while (newUDPVal(failure, argForUDPVal, bindingMade, bindings, starBindings, constraints, cb)) {
- if (((next != null) &&
- next.findOrCreate(remLitsCopy, starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb, pcStr, dyad))
- || ((next == null) &&
- negatedConstraintsSatisfied(starStuff, bindings, badBindings, starBindings, constraints, kinTerm, cb)))
- return true;
- } // end of while-loop.
- } // end of it-was-a-Variabe-for-a-person
- } // end of there is a UDP constraint for this bound-arg
- } // end of failed-due-to-a-UDP-value
- // retract any binding made - put it on BadBindings list. retract property bindings, too
- updateBindingsEtc(bindings, badBindings, bindingMade, argBound, starBindings, sbSize);
- cb.starCounter--; // un-do the counter increment
- if (argBound == personVar) undoPersonalStarLink(person, predicate.name, bindings);
- if (pcStr.size() >= 1) pcStr.remove(pcStr.size() -1); // retract the PC-String addition
- if (dyad != null && dyad.path.size() > 0) dyad.path.remove(dyad.path.size() -1);
- if (tryFlag++ < 2) {
- if (findOrCreateStarLink(remLits, starStuff, bindings, badBindings, starBindings, constraints,
- tryFlag, true, kinTerm, cb, pcStr, dyad))
- return true;
- // if we get this far, all binding attempts have failed. Pass failure up to next higher level.
- // keepBB determines whether we retain our record of badBindings at this level.
- // If we're about to send a FAIL back to a higher-level literal in the chain, we want to
- // erase them. But if we're FAILing back to an earlier iteration at this level, keep them.
- // In EITHER case, make sure any property bindings have been undone.
- updateBindingsEtc(bindings, badBindings, null, null, starBindings, sbSize);
- }
- if (! keepBB) {
- badBindingsRemove(bindingMade, argBound, badBindings);
- Context.current.resetTo(resetInd, resetFam);
- } // end of don't-keep-badBindings
- return false;
- // end of recursive-descent-or-negatedConstraints-failed
- } // end of method findOrCreateStarLink
- public void createPersonalStarLink(Individual person2, String predName, ArrayList<Object> starBindings)
- throws KSInternalErrorException {
- // Find the person, via starBindings, who has the link to person2
- for (int i = starBindings.size() -1; i >= 0; i--) {
- StarPropertyBinding spb = (StarPropertyBinding)starBindings.get(i);
- if (spb.starPropName.equals(predName) && spb.personBound != null && spb.personBound != person2) {
- Individual person1 = spb.personBound;
- if (person1.starLinks == null) person1.starLinks = new ArrayList<Object>();
- if (! person1.starLinks.contains(person2)) person1.starLinks.add(person2);
- if (person2.starLinks == null) person2.starLinks = new ArrayList<Object>();
- if (! person2.starLinks.contains(person1)) person2.starLinks.add(person1);
- return;
- } // end of found-a-match
- } // end of backwards loop thru SPBs
- Context.breakpoint();
- throw new KSInternalErrorException("Lit2.createPersonalStarLink failed to find origin of " + predName
- + "_link to " + person2);
- } // end of method createPersonalStarLink
- public void undoPersonalStarLink(Individual linkee, String predName, TreeMap bindings)
- throws KSInternalErrorException {
- // search bindings for a person who has a starLink of type predName to linkee
- Iterator boundIter = bindings.values().iterator();
- while (boundIter.hasNext()) {
- Object it = boundIter.next();
- if (it instanceof Individual) {
- Individual ind = (Individual) it;
- if (ind.starLinks …
Large files files are truncated, but you can click here to view the full file