package edu.stanford.nlp.ie.machinereading.structure;
import edu.stanford.nlp.util.logging.Redwood;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import edu.stanford.nlp.ie.machinereading.structure.MachineReadingAnnotations;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.util.CoreMap;
import edu.stanford.nlp.util.IdentityHashSet;
/**
*
* @author Andrey Gusev
* @author Mihai
*
*/
public class EventMention extends RelationMention {
/** A logger for this class */
private static Redwood.RedwoodChannels log = Redwood.channels(EventMention.class);
private static final long serialVersionUID = 1L;
/** Modifier argument: used for BioNLP */
private String eventModification;
private final ExtractionObject anchor;
// this is set if we're a subevent
// we might have multiple parents for the same event (at least in the reader before sanity check 4)!
private Set<ExtractionObject> parents;
public EventMention(String objectId,
CoreMap sentence,
Span span,
String type,
String subtype,
ExtractionObject anchor,
List<ExtractionObject> args,
List<String> argNames) {
super(objectId, sentence, span, type, subtype, args, argNames);
this.anchor = anchor;
this.parents = new IdentityHashSet<>();
// set ourselves as the parent of any EventMentions in our args
for (ExtractionObject arg : args) {
if (arg instanceof EventMention) {
((EventMention) arg).addParent(this);
}
}
}
public void resetArguments() {
args = new ArrayList<>();
argNames = new ArrayList<>();
}
public void removeFromParents() {
// remove this from the arg list of all parents
for(ExtractionObject parent: parents){
if(parent instanceof RelationMention){
((RelationMention) parent).removeArgument(this, false);
}
}
// reset the parent links
parents.clear();
}
public void removeParent(ExtractionObject p) {
parents.remove(p);
}
public String getModification() {
return eventModification;
}
public void setModification(String eventModification) {
this.eventModification = eventModification;
}
public ExtractionObject getAnchor() {
return anchor;
}
/**
* If this EventMention is a subevent, this will return the parent event.
*
* @return the parent EventMention or null if this isn't a subevent.
*/
public Set<ExtractionObject> getParents() {
return parents;
}
public ExtractionObject getSingleParent(CoreMap sentence) {
if(getParents().size() > 1){
Set<ExtractionObject> parents = getParents();
log.info("This event has multiple parents: " + this);
int count = 1;
for(ExtractionObject po: parents){
log.info("PARENT #" + count + ": " + po);
count ++;
}
log.info("DOC " + sentence.get(CoreAnnotations.DocIDAnnotation.class));
log.info("SENTENCE:");
for(CoreLabel t: sentence.get(CoreAnnotations.TokensAnnotation.class)){
log.info(" " + t.word());
}
log.info("EVENTS IN SENTENCE:");
count = 1;
for(EventMention e: sentence.get(MachineReadingAnnotations.EventMentionsAnnotation.class)){
log.info("EVENT #" + count + ": " + e);
count ++;
}
}
assert(getParents().size() <= 1);
for(ExtractionObject p: getParents()){
return p;
}
return null;
}
public void addParent(EventMention p) {
parents.add(p);
}
@Override
public String toString() {
return "EventMention [objectId=" + getObjectId() + ", type=" + type + ", subType=" + subType
+ ", start=" + getExtentTokenStart() + ", end=" + getExtentTokenEnd()
+ (anchor != null ? ", anchor=" + anchor : "")
+ (args != null ? ", args=" + args : "")
+ (argNames != null ? ", argNames=" + argNames : "") + "]";
}
public boolean contains(EventMention e) {
if(this == e) return true;
for(ExtractionObject a: getArgs()){
if(a instanceof EventMention){
EventMention ea = (EventMention) a;
if(ea.contains(e)){
return true;
}
}
}
return false;
}
public void addArg(ExtractionObject a, String an, boolean discardSameArgDifferentName) {
// only add if not already an argument
for(int i = 0; i < getArgs().size(); i ++){
ExtractionObject myArg = getArg(i);
String myArgName = getArgNames().get(i);
if(myArg == a){
if(myArgName.equals(an)){
// safe to discard this arg: we already have it with the same name
return;
} else {
logger.info("Trying to add one argument: " + a + " with name " + an + " when this already exists with a different name: " + this + " in sentence: " + getSentence().get(CoreAnnotations.TextAnnotation.class));
if(discardSameArgDifferentName) return;
}
}
}
this.args.add(a);
this.argNames.add(an);
if(a instanceof EventMention){
((EventMention) a).addParent(this);
}
}
@Override
public void setArgs(List<ExtractionObject> args) {
this.args = args;
// set ourselves as the parent of any EventMentions in our args
for (ExtractionObject arg : args) {
if (arg instanceof EventMention) {
((EventMention) arg).addParent(this);
}
}
}
public void addArgs(List<ExtractionObject> args, List<String> argNames, boolean discardSameArgDifferentName){
if(args == null) return;
assert (args.size() == argNames.size());
for(int i = 0; i < args.size(); i ++){
addArg(args.get(i), argNames.get(i), discardSameArgDifferentName);
}
}
public void mergeEvent(EventMention e, boolean discardSameArgDifferentName){
// merge types if necessary
String oldType = type;
type = ExtractionObject.concatenateTypes(type, e.getType());
if(! type.equals(oldType)){
// This is not important: we use anchor types in the parser, not event types
// This is done just for completeness of code
logger.fine("Type changed from " + oldType + " to " + type + " during check 3 merge.");
}
// add e's arguments
for(int i = 0; i < e.getArgs().size(); i ++){
ExtractionObject a = e.getArg(i);
String an = e.getArgNames().get(i);
// TODO: we might need more complex cycle detection than just contains()...
if(a instanceof EventMention && ((EventMention) a).contains(this)){
logger.info("Found event cycle during merge between e1 " + this + " and e2 " + e);
} else {
// remove e from a's parents
if(a instanceof EventMention) ((EventMention) a).removeParent(e);
// add a as an arg to this
addArg(a, an, discardSameArgDifferentName);
}
}
// remove e's arguments. they are now attached to this, so we don't want them moved around during removeEvents
e.resetArguments();
// remove e from its parent(s) to avoid using this argument in other merges of the parent
e.removeFromParents();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EventMention)) return false;
if (!super.equals(o)) return false;
EventMention that = (EventMention) o;
if (anchor != null ? !anchor.equals(that.anchor) : that.anchor != null) return false;
if (eventModification != null ? !eventModification.equals(that.eventModification) : that.eventModification != null)
return false;
if (parents != null ? !parents.equals(that.parents) : that.parents != null) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (eventModification != null ? eventModification.hashCode() : 0);
result = 31 * result + (anchor != null ? anchor.hashCode() : 0);
return result;
}
}