argument querying in copular transfer eval
All checks were successful
studiorailgun/trpg/pipeline/head This commit looks good
All checks were successful
studiorailgun/trpg/pipeline/head This commit looks good
This commit is contained in:
parent
4c75cdc07a
commit
05122a844e
@ -1,20 +1,18 @@
|
||||
package org.studiorailgun.ai.conversation.evaluators.transfer;
|
||||
|
||||
import org.studiorailgun.Globals;
|
||||
import org.studiorailgun.ai.conversation.evaluators.query.NounStack;
|
||||
import org.studiorailgun.ai.conversation.parser.NLPDependencies;
|
||||
import org.studiorailgun.ai.conversation.parser.PennTreebankTagSet;
|
||||
import org.studiorailgun.ai.conversation.parser.depend.Argument;
|
||||
import org.studiorailgun.ai.conversation.parser.depend.Clause;
|
||||
import org.studiorailgun.ai.conversation.parser.depend.Predicate;
|
||||
import org.studiorailgun.ai.conversation.tracking.Conversation;
|
||||
import org.studiorailgun.ai.conversation.tracking.Quote;
|
||||
import org.studiorailgun.ai.conversation.tracking.Sentence;
|
||||
import org.studiorailgun.ai.conversation.web.ArgumentQuery;
|
||||
import org.studiorailgun.ai.knowledge.Node;
|
||||
import org.studiorailgun.ai.knowledge.query.NodePropQuery;
|
||||
|
||||
import edu.stanford.nlp.ling.IndexedWord;
|
||||
import edu.stanford.nlp.semgraph.SemanticGraph;
|
||||
import edu.stanford.nlp.trees.GrammaticalRelation;
|
||||
|
||||
/**
|
||||
* Evaluates a transfer statement
|
||||
@ -35,21 +33,22 @@ public class TransferEval {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
IndexedWord root = semanticGraph.getFirstRoot();
|
||||
Clause mainClause = sentence.getMainClause();
|
||||
Predicate pred = mainClause.getPredicate();
|
||||
|
||||
if(PennTreebankTagSet.isNoun(root.tag())){
|
||||
if(TransferEval.isCopularStatement(semanticGraph)){
|
||||
NounStack noun1 = NounStack.parse(semanticGraph, root);
|
||||
NounStack noun2 = null;
|
||||
for(IndexedWord child : semanticGraph.getChildList(root)){
|
||||
if(PennTreebankTagSet.isNoun(child.tag())){
|
||||
noun2 = NounStack.parse(semanticGraph, child);
|
||||
break;
|
||||
}
|
||||
if(TransferEval.isCopularStatement(pred)){
|
||||
//this is a copular predicate
|
||||
Argument argument1 = mainClause.getSubject();
|
||||
Argument argument2 = mainClause.getPredicate().getCopularArg();
|
||||
if(argument1 == null || argument2 == null){
|
||||
String message = "Failed to parse arguments for copular statement! \n" +
|
||||
argument1 + " " + argument2 + "\n" +
|
||||
sentence.getRaw() + "\n" +
|
||||
semanticGraph;
|
||||
throw new Error(message);
|
||||
}
|
||||
if(noun2 == null){
|
||||
throw new Error("Failed to parse second noun! " + semanticGraph);
|
||||
}
|
||||
TransferEval.evaluateCopularStatement(conversation, quote, sentence, noun1, null);
|
||||
TransferEval.evaluateCopularStatement(conversation, quote, sentence, argument1, argument2);
|
||||
} else {
|
||||
String message = "Unsupported root type!\n" +
|
||||
"\"" + sentence.getRaw() + "\"\n" +
|
||||
@ -72,11 +71,11 @@ public class TransferEval {
|
||||
* @param noun1 The first noun stack
|
||||
* @param noun2 The second noun stack
|
||||
*/
|
||||
private static void evaluateCopularStatement(Conversation conversation, Quote quote, Sentence sentence, NounStack noun1, NounStack noun2){
|
||||
private static void evaluateCopularStatement(Conversation conversation, Quote quote, Sentence sentence, Argument subject, Argument object){
|
||||
SemanticGraph graph = sentence.getGraph();
|
||||
IndexedWord verb = NLPDependencies.getCopular(graph);
|
||||
if(PennTreebankTagSet.isBe(verb.tag())){
|
||||
TransferEval.evaluateAssignmentStatement(conversation, quote, sentence, noun1, noun2);
|
||||
TransferEval.evaluateAssignmentStatement(conversation, quote, sentence, subject, object);
|
||||
} else {
|
||||
throw new Error("Unsupported verb type! " + graph);
|
||||
}
|
||||
@ -88,18 +87,20 @@ public class TransferEval {
|
||||
* @param quote The quote
|
||||
* @param sentence The sentence
|
||||
*/
|
||||
private static void evaluateAssignmentStatement(Conversation conversation, Quote quote, Sentence sentence, NounStack noun1, NounStack noun2){
|
||||
private static void evaluateAssignmentStatement(Conversation conversation, Quote quote, Sentence sentence, Argument subjectArg, Argument objectArg){
|
||||
//if there is no node with this name already, create one
|
||||
System.out.println(sentence.getGraph());
|
||||
Clause mainClause = sentence.getMainClause();
|
||||
String noun1RootText = noun1.getIndexedWord().originalText();
|
||||
if(NodePropQuery.byName(noun1RootText).size() < 1){
|
||||
Globals.web.createNode(noun1RootText);
|
||||
|
||||
Node subjectNode = ArgumentQuery.getArgument(quote, subjectArg);
|
||||
if(subjectNode == null){
|
||||
throw new Error("Error querying subject!");
|
||||
}
|
||||
|
||||
Node subject = ArgumentQuery.getArgument(quote, mainClause.getSubject());
|
||||
// Node object = ArgumentQuery.getArgument(quote, mainClause.getDirectObject());
|
||||
//make an equivalence link here
|
||||
Node objectNode = ArgumentQuery.getArgument(quote, objectArg);
|
||||
if(objectNode == null){
|
||||
throw new Error("Error querying object!");
|
||||
}
|
||||
//make an equivalence link here if it doesn't exist already
|
||||
|
||||
//for the moment, assume the other noun is a concept
|
||||
|
||||
@ -107,18 +108,11 @@ public class TransferEval {
|
||||
|
||||
/**
|
||||
* Checks if this is a copular statement
|
||||
* @param graph The graph
|
||||
* @param pred The predicate of the sentence
|
||||
* @return true if it is a copular statement, false otherwise
|
||||
*/
|
||||
private static boolean isCopularStatement(SemanticGraph graph){
|
||||
IndexedWord root = graph.getFirstRoot();
|
||||
for(IndexedWord child : graph.getChildList(root)){
|
||||
GrammaticalRelation relation = graph.reln(root,child);
|
||||
if(NLPDependencies.isCopular(relation.getLongName())){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
private static boolean isCopularStatement(Predicate pred){
|
||||
return pred.getCopular() != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -79,6 +79,23 @@ public class PennTreebankTagSet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this is a proper noun or not
|
||||
* @param tag The tag
|
||||
* @return true if it is a proper noun, false otherwise
|
||||
*/
|
||||
public static boolean isCommonNoun(String tag){
|
||||
switch(tag){
|
||||
case "NN":
|
||||
case "NNS": {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tag is a proper noun or not
|
||||
* @param tag The tag
|
||||
@ -87,7 +104,8 @@ public class PennTreebankTagSet {
|
||||
public static boolean isProperNoun(String tag){
|
||||
switch(tag){
|
||||
case "NP":
|
||||
case "NPS": {
|
||||
case "NPS":
|
||||
case "NNP": {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
|
||||
@ -123,6 +123,21 @@ public class Argument {
|
||||
rVal.adverb = child;
|
||||
} break;
|
||||
|
||||
|
||||
//this will have already been parsed at the clause level, want to ignore now
|
||||
case "advcl_preposition":
|
||||
//this will have already been parsed at the clause level, want to ignore now
|
||||
case "parataxis":
|
||||
//this will have already been parsed at the clause level, want to ignore now
|
||||
case "punctuation":
|
||||
//this will have already been parsed at the clause level, want to ignore now
|
||||
case "copula":
|
||||
//this can occur when we are parsing the root nominal of a non-verbal copular sentence -- we would expect the root to point at the subject of the copular and we don't want that subject to be a part of this argument
|
||||
case "nominal subject": {
|
||||
//cases to ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
//unhandled cases
|
||||
default: {
|
||||
throw new Error("Unsupported relation type! " + relation.getLongName() + "\n" + "for " + child.originalText() + "\n" + graph);
|
||||
|
||||
@ -131,6 +131,8 @@ public class Clause {
|
||||
case "copula": {
|
||||
//this means the root is a noun, but this related word is turning it into a copular predicate
|
||||
pred.setCopular(child);
|
||||
Argument copularArg = Argument.parse(graph, pred.getRoot(), ArgumentType.NOMINAL);
|
||||
pred.setCopularArg(copularArg);
|
||||
} break;
|
||||
|
||||
//a prepositional adjunct (oblique)
|
||||
|
||||
@ -87,6 +87,11 @@ public class Predicate {
|
||||
*/
|
||||
IndexedWord copularVerb;
|
||||
|
||||
/**
|
||||
* The argument that this predicate is storing given that it is a copular predicate
|
||||
*/
|
||||
Argument copularArg;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param root The root of the predicate
|
||||
@ -135,6 +140,22 @@ public class Predicate {
|
||||
return this.copularVerb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the copular argument for this predicate
|
||||
* @param arg The copular argument
|
||||
*/
|
||||
public void setCopularArg(Argument arg){
|
||||
this.copularArg = arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the copular argument for this predicate
|
||||
* @return The copular argument
|
||||
*/
|
||||
public Argument getCopularArg(){
|
||||
return copularArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the existential status of the predicate
|
||||
* @param existential true if existential, false otherwise
|
||||
|
||||
@ -84,6 +84,14 @@ public class Quote {
|
||||
public void setNode(Node node){
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node corresponding to this quote
|
||||
* @return The node
|
||||
*/
|
||||
public Node getNode(){
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,8 +1,17 @@
|
||||
package org.studiorailgun.ai.conversation.web;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.studiorailgun.Globals;
|
||||
import org.studiorailgun.ai.conversation.parser.PennTreebankTagSet;
|
||||
import org.studiorailgun.ai.conversation.parser.depend.Argument;
|
||||
import org.studiorailgun.ai.conversation.tracking.Quote;
|
||||
import org.studiorailgun.ai.knowledge.Node;
|
||||
import org.studiorailgun.ai.knowledge.Relation;
|
||||
import org.studiorailgun.ai.knowledge.query.InstanceQuery;
|
||||
import org.studiorailgun.ai.knowledge.types.RelationTypes;
|
||||
import org.studiorailgun.ai.linguistics.ProperNounQuery;
|
||||
import org.studiorailgun.ai.philosophy.ConceptQuery;
|
||||
|
||||
/**
|
||||
@ -18,19 +27,22 @@ public class ArgumentQuery {
|
||||
*/
|
||||
public static Node getArgument(Quote quote, Argument argument){
|
||||
String argumentRoot = argument.getRoot().originalText();
|
||||
String argumentTag = argument.getRoot().tag();
|
||||
|
||||
//the root node which then had modifiers applied to it
|
||||
Node rootNode = null;
|
||||
|
||||
Node conceptNode = ConceptQuery.getConcept(argumentRoot);
|
||||
if(conceptNode != null){
|
||||
if(PennTreebankTagSet.isCommonNoun(argumentTag)){
|
||||
Node conceptNode = ConceptQuery.getConcept(argumentRoot);
|
||||
rootNode = conceptNode;
|
||||
//apply possessive modifier
|
||||
if(argument.getPossessiveModifier() != null){
|
||||
rootNode = ArgumentQuery.getPossessionModified(quote, rootNode, argument);
|
||||
}
|
||||
} else if(PennTreebankTagSet.isProperNoun(argumentTag)) {
|
||||
rootNode = ProperNounQuery.getProperNoun(argumentRoot);
|
||||
} else {
|
||||
throw new Error("TODO: solve for proper nouns");
|
||||
throw new Error("Undefined case! " + argumentTag);
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
@ -47,7 +59,21 @@ public class ArgumentQuery {
|
||||
String possessionModifier = argument.getPossessiveModifier().originalText().toLowerCase();
|
||||
switch(possessionModifier){
|
||||
case "my": {
|
||||
|
||||
List<Node> instances = InstanceQuery.getInstances(rootNode);
|
||||
List<Node> possessedInstances = instances.stream().filter(node -> {
|
||||
List<Relation> relations = Globals.web.getRelationsOfChildNode(node);
|
||||
List<Relation> possessionRelationsToRoot = relations.stream().filter(relation -> relation.getName().equals(RelationTypes.POSSESSION_OF) && relation.getParent().equals(rootNode)).collect(Collectors.toList());
|
||||
return possessionRelationsToRoot.size() > 0;
|
||||
}).collect(Collectors.toList());
|
||||
if(possessedInstances.size() == 1){
|
||||
//already exists, return it
|
||||
rVal = possessedInstances.get(0);
|
||||
} else if(possessedInstances.size() > 1) {
|
||||
//already exists, return it
|
||||
throw new Error("Can't currently handle plural instances!");
|
||||
} else {
|
||||
//does not already exist, see if we can generate a node to encapsulate it
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
throw new Error("Unsupported possession modifier! " + possessionModifier);
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
package org.studiorailgun.ai.conversation.web;
|
||||
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -27,4 +31,18 @@ public class QuoteQuery {
|
||||
Globals.web.createRelation(RelationTypes.MEMBER_OF, conversation, quote);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the speaker of a quote
|
||||
* @param quote The quote
|
||||
* @return The speaker of the quote
|
||||
*/
|
||||
public static Node getSpeaker(Node quote){
|
||||
List<Relation> relations = Globals.web.getRelationsOfChildNode(quote);
|
||||
List<Node> speakers = relations.stream().filter(relation -> relation.getName().equals(RelationTypes.QUOTE_OF)).map(relation -> relation.getParent()).collect(Collectors.toList());
|
||||
if(speakers.size() != 1){
|
||||
throw new Error("Invalid number of speakers! " + speakers.size());
|
||||
}
|
||||
return speakers.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -254,6 +254,14 @@ public class KnowledgeWeb {
|
||||
return nodes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of all nodes
|
||||
* @return The collection
|
||||
*/
|
||||
public List<Node> getNodesList() {
|
||||
return new LinkedList<Node>(nodes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection of all relations
|
||||
* @return The collection of all relations
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
package org.studiorailgun.ai.linguistics;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.studiorailgun.Globals;
|
||||
import org.studiorailgun.ai.conversation.parser.depend.Argument;
|
||||
import org.studiorailgun.ai.conversation.tracking.Quote;
|
||||
import org.studiorailgun.ai.conversation.web.QuoteQuery;
|
||||
import org.studiorailgun.ai.knowledge.Node;
|
||||
import org.studiorailgun.ai.knowledge.Relation;
|
||||
import org.studiorailgun.ai.knowledge.query.InstanceQuery;
|
||||
import org.studiorailgun.ai.knowledge.types.RelationTypes;
|
||||
|
||||
/**
|
||||
* Queries related to possession
|
||||
*/
|
||||
public class PosessionQuery {
|
||||
|
||||
/**
|
||||
* Gets the root node with the possession modifier applied
|
||||
* @param rootNode The root node
|
||||
* @param argument The argument
|
||||
* @return The node that represents the possession modifier applied to the root node
|
||||
*/
|
||||
public static Node getPossessionModified(Quote quote, Node rootNode, Argument argument){
|
||||
Node rVal = rootNode;
|
||||
String possessionModifier = argument.getPossessiveModifier().originalText().toLowerCase();
|
||||
switch(possessionModifier){
|
||||
case "my": {
|
||||
List<Node> instances = InstanceQuery.getInstances(rootNode);
|
||||
List<Node> possessedInstances = instances.stream().filter((Node node) -> {
|
||||
List<Relation> relations = Globals.web.getRelationsOfChildNode(node);
|
||||
List<Relation> possessionRelationsToRoot = relations.stream().filter(relation -> relation.getName().equals(RelationTypes.POSSESSION_OF) && relation.getParent().equals(rootNode)).collect(Collectors.toList());
|
||||
return possessionRelationsToRoot.size() > 0;
|
||||
}).collect(Collectors.toList());
|
||||
if(possessedInstances.size() == 1){
|
||||
//already exists, return it
|
||||
rVal = possessedInstances.get(0);
|
||||
} else if(possessedInstances.size() > 1) {
|
||||
//already exists, return it
|
||||
throw new Error("Can't currently handle plural instances!");
|
||||
} else {
|
||||
rVal = PosessionQuery.generatePossessionModified(quote, rootNode, argument);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
throw new Error("Unsupported possession modifier! " + possessionModifier);
|
||||
}
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a node to fill in the instance of the possessor owning an instance of the root node
|
||||
* @param quote The quote
|
||||
* @param rootNode The root node
|
||||
* @param argument The argument
|
||||
* @return The generated node
|
||||
*/
|
||||
private static Node generatePossessionModified(Quote quote, Node rootNode, Argument argument){
|
||||
Node possession = Globals.web.createNode("possession(inst)");
|
||||
|
||||
//attach to concept
|
||||
Globals.web.createRelation(RelationTypes.INSTANCE_OF, rootNode, possession);
|
||||
|
||||
//attach to speaker
|
||||
Node possessor = QuoteQuery.getSpeaker(quote.getNode());
|
||||
Globals.web.createRelation(RelationTypes.POSSESSION_OF, possessor, possession);
|
||||
|
||||
return possession;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package org.studiorailgun.ai.linguistics;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.studiorailgun.Globals;
|
||||
import org.studiorailgun.ai.knowledge.Node;
|
||||
|
||||
/**
|
||||
* Queries related to proper nouns
|
||||
*/
|
||||
public class ProperNounQuery {
|
||||
|
||||
/**
|
||||
* Tries to locate a proper noun
|
||||
* @param properNoun The proper noun
|
||||
* @return The node representing the proper noun
|
||||
*/
|
||||
public static Node getProperNoun(String properNoun){
|
||||
Node rVal = null;
|
||||
List<Node> nodes = Globals.web.getNodesList().stream().filter(node -> node.getName().equals(properNoun)).collect(Collectors.toList());
|
||||
if(nodes.size() < 1){
|
||||
//create a name node to represent this name
|
||||
rVal = Globals.web.createNode(properNoun);
|
||||
} else if(nodes.size() == 1){
|
||||
rVal = nodes.get(0);
|
||||
} else {
|
||||
throw new Error("More than one proper match found! " + nodes.size());
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user