diff --git a/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java b/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java index 7bd9663..9bcf7f9 100644 --- a/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java +++ b/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java @@ -11,6 +11,7 @@ import org.studiorailgun.ai.conversation.tracking.Sentence; import org.studiorailgun.ai.conversation.web.ArgumentQuery; import org.studiorailgun.ai.conversation.web.MetaQuery; import org.studiorailgun.ai.knowledge.Node; +import org.studiorailgun.ai.knowledge.cleaning.CollapseRelations; import edu.stanford.nlp.ling.IndexedWord; import edu.stanford.nlp.semgraph.SemanticGraph; @@ -102,18 +103,15 @@ public class TransferEval { throw new Error("Error querying object!"); } //make an equivalence link here if it doesn't exist already - if(MetaQuery.isLearnable(subjectNode)){ - - } else if(MetaQuery.isLearnable(objectNode)){ - + if(MetaQuery.isLearnable(subjectNode) || MetaQuery.isLearnable(objectNode)){ + MetaQuery.equate(subjectNode, objectNode); + CollapseRelations.collapse(subjectNode); + CollapseRelations.collapse(objectNode); } else { String message = "Information already stored?\n" + sentence.getGraph(); throw new Error(message); } - - //for the moment, assume the other noun is a concept - } /** diff --git a/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java b/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java index dd1c876..323b486 100644 --- a/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java +++ b/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java @@ -38,6 +38,15 @@ public class MetaQuery { return discoveredLearnable.size() > 0; } + /** + * Equates two nodes + * @param node1 The first node + * @param node2 The second node + */ + public static void equate(Node node1, Node node2){ + Globals.web.createRelation(RelationTypes.EQUALS, node1, node2); + Globals.web.createRelation(RelationTypes.EQUALS, node2, node1); + } } diff --git a/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java b/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java index c530470..7c21c34 100644 --- a/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java +++ b/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java @@ -323,7 +323,7 @@ public class KnowledgeWeb { } /** - * Gets the relations where the provided node is the parent of the relationship + * Gets the relations where the provided node is the child of the relationship * @param node The node * @return The list of relations */ diff --git a/src/main/java/org/studiorailgun/ai/knowledge/cleaning/CollapseRelations.java b/src/main/java/org/studiorailgun/ai/knowledge/cleaning/CollapseRelations.java new file mode 100644 index 0000000..9ef1b34 --- /dev/null +++ b/src/main/java/org/studiorailgun/ai/knowledge/cleaning/CollapseRelations.java @@ -0,0 +1,23 @@ +package org.studiorailgun.ai.knowledge.cleaning; + +import org.studiorailgun.ai.knowledge.Node; +import org.studiorailgun.ai.linguistics.NameCollapse; + +/** + * Scans for complex relations and collapses them into richer ones that represent the same information + * ie, + * person(inst) <--possessionOf-- name(inst) --equals--> "John" + * collapses to + * person(inst) <-- nameOf -- "John" + */ +public class CollapseRelations { + + /** + * Scans a node for relations to collapse + * @param node The node to scan + */ + public static void collapse(Node node){ + NameCollapse.collapse(node); + } + +} diff --git a/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java b/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java index e956336..96668f5 100644 --- a/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java +++ b/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java @@ -35,4 +35,9 @@ public class RelationTypes { */ public static final String MEMBER_OF = "memberOf"; + /** + * The two nodes are equivalent + */ + public static final String EQUALS = "equals"; + } diff --git a/src/main/java/org/studiorailgun/ai/linguistics/NameCollapse.java b/src/main/java/org/studiorailgun/ai/linguistics/NameCollapse.java new file mode 100644 index 0000000..5e5af74 --- /dev/null +++ b/src/main/java/org/studiorailgun/ai/linguistics/NameCollapse.java @@ -0,0 +1,102 @@ +package org.studiorailgun.ai.linguistics; + +import java.util.stream.Collectors; + +import org.studiorailgun.Globals; +import org.studiorailgun.ai.knowledge.Node; +import org.studiorailgun.ai.knowledge.Relation; +import org.studiorailgun.ai.knowledge.types.RelationTypes; +import org.studiorailgun.ai.philosophy.ConceptQuery; + +/** + * Collapse functions for name relations + */ +public class NameCollapse { + + /** + * Scans a node for relations to collapse + * @param node The node to scan + */ + public static void collapse(Node node){ + Node nameConcept = ConceptQuery.getConcept("name"); + if(nameConcept == null){ + throw new Error("Name concept undefined!"); + } + + boolean shouldAttemptPossessionSubstitution = false; + for(Relation childRelation : Globals.web.getRelationsOfChildNode(node)){ + switch(childRelation.getName()){ + case RelationTypes.INSTANCE_OF: { + /** + * Collapse names + * person(inst) <--possessionOf-- name(inst) --equals--> "John" + * collapses to + * person(inst) <-- nameOf -- "John" + */ + if(childRelation.getParent().equals(nameConcept)){ + shouldAttemptPossessionSubstitution = true; + } + } break; + default: { + } break; + } + } + // for(Relation parentRelations : Globals.web.getRelationsOfParentNode(node)){ + // } + if(shouldAttemptPossessionSubstitution){ + NameCollapse.attemptPossessionSubstitution(node); + } + } + + /** + * Attents an equivalence-to-"nameOf" substitution + * @param node The node + */ + private static void attemptPossessionSubstitution(Node node){ + Node nameConcept = ConceptQuery.getConcept("name"); + if(nameConcept == null){ + throw new Error("Name concept undefined!"); + } + + boolean shouldAttemptPossessionSubstitution = false; + for(Relation childRelation : Globals.web.getRelationsOfChildNode(node)){ + switch(childRelation.getName()){ + case RelationTypes.INSTANCE_OF: { + /** + * Collapse names + * person(inst) <--possessionOf-- name(inst) --equals--> "John" + * collapses to + * person(inst) <-- nameOf -- "John" + */ + if(childRelation.getParent().equals(nameConcept)){ + shouldAttemptPossessionSubstitution = true; + } + } break; + default: { + } break; + } + } + if(shouldAttemptPossessionSubstitution){ + Node properNoun = null; + Node possessor = null; + //get the proper noun + for(Relation childRelation : Globals.web.getRelationsOfChildNode(node).stream().filter(relation -> relation.getName().equals(RelationTypes.EQUALS)).collect(Collectors.toList())){ + properNoun = childRelation.getParent(); + break; + } + if(properNoun == null){ + throw new Error("Failed to find the proper noun to perform the substitution with!"); + } + //get the proper noun + for(Relation childRelation : Globals.web.getRelationsOfChildNode(node).stream().filter(relation -> relation.getName().equals(RelationTypes.POSSESSION_OF)).collect(Collectors.toList())){ + possessor = childRelation.getParent(); + break; + } + if(possessor == null){ + throw new Error("Failed to find the possessor to perform the substitution with!"); + } + NameQuery.attachName(properNoun, possessor); + } + } + +} diff --git a/src/main/java/org/studiorailgun/ai/linguistics/NameQuery.java b/src/main/java/org/studiorailgun/ai/linguistics/NameQuery.java index 8ecb987..761ee7c 100644 --- a/src/main/java/org/studiorailgun/ai/linguistics/NameQuery.java +++ b/src/main/java/org/studiorailgun/ai/linguistics/NameQuery.java @@ -21,4 +21,13 @@ public class NameQuery { return relations.stream().filter(relation -> relation.getName().equals(RelationTypes.NAME_OF)).map(relation -> relation.getParent()).collect(Collectors.toList()); } + /** + * Attaches a name to a child + * @param properNoun The proper noun + * @param child The child + */ + public static void attachName(Node properNoun, Node child){ + Globals.web.createRelation(RelationTypes.NAME_OF, properNoun, child); + } + } diff --git a/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java b/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java index b0fdfd6..b1dd372 100644 --- a/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java +++ b/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java @@ -31,7 +31,7 @@ public class TransferEvaluationTests { //search for the name being assigned in the knowledge web Node otherParticipant = ConversationQuery.getOtherParticipant(); List names = NameQuery.getNames(otherParticipant); - // assertEquals(names.get(0).getName(),"John"); + assertEquals(names.get(0).getName(),"John"); } }