code: package caevo.sieves;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import caevo.SieveDocument;
  import caevo.SieveDocuments;
  import caevo.SieveSentence;
  import caevo.TextEvent;
  import caevo.Timex;
  import caevo.tlink.EventEventLink;
  import caevo.tlink.EventTimeLink;
  import caevo.tlink.TLink;
  import caevo.util.Pair;
  import caevo.util.TreeOperator;
  import edu.stanford.nlp.trees.Tree;
  import edu.stanford.nlp.trees.TypedDependency;
  
  /**
   * This sieve deals with nominal events. These are almost always vague without
   * an understanding of the lexical semantics. We're stuck. In the end, this
   * sieve does some very precise but RARE things: 1. Timex modifiers for
   * event-time links: "three-year war" 2. Temporal prepositions for event-event
   * links: "left after the bombing"
   * 
   * I tested lots of other things, such as indefinite and definite nominals. The
   * distribution on both is uniform with the DCT, and bares no obvious
   * relationships with other verbal events.
   * 
   * 
   * precision = 0.813 13 of 16
   * 
   * @author chambers
   */
  public class NominalEvents implements Sieve {
  
    /**
     * The main function. All sieves must have this.
     */
    public List<TLink> annotate(SieveDocument doc, List<TLink> currentTLinks) {
      List<TLink> proposed = new ArrayList<TLink>();
      for (SieveSentence sent : doc.getSentences()) {
        List<TextEvent> events = sent.events();
        List<Tree> trees = doc.getAllParseTrees();
        // List<TypedDependency> deps = sent.getDeps();
  
        for (int ii = 0; ii < events.size(); ii++) {
          TextEvent event = events.get(ii);
          String pos = TreeOperator.indexToPOSTag(trees.get(event.getSid()),
              event.getIndex());
          // System.out.println("EVENT: " + event + " index: " +
          // (event.getIndex()) + " pos: " + pos);
  
          if (pos != null && pos.startsWith("NN")) {
            // System.out.println("Nominal event: " + event);
            // System.out.println("\t" + sent.sentence());
  
            // EVENT-TIMEX links: if it has a timex modifier
            Pair<Timex, TypedDependency> keytimex = getAttachedTimex(sent, event);
            if (keytimex != null) {
              Timex theTimex = keytimex.first();
              TypedDependency dep = keytimex.second();
              String reln = dep.reln().toString();
  
              // "the two-hour meeting", "two-week crisis", "eight-year war"
              // (amod should be time duration modifiers, so these are
              // simultaneous)
              if (reln.equalsIgnoreCase("amod"))
                proposed.add(new EventTimeLink(event.getEiid(), theTimex.getTid(),
                    TLink.Type.SIMULTANEOUS));
  
              // "Aug 9 power grab", "Aug 17 cease fire"
              if (reln.equalsIgnoreCase("nn"))
                proposed.add(new EventTimeLink(event.getEiid(), theTimex.getTid(),
                    TLink.Type.IS_INCLUDED));
  
              // "today's quiz"
              if (reln.equalsIgnoreCase("poss"))
                proposed.add(new EventTimeLink(event.getEiid(), theTimex.getTid(),
                    TLink.Type.IS_INCLUDED));
  
              // "kidnappings in recent years"
              if (reln.equalsIgnoreCase("prep_in"))
                proposed.add(new EventTimeLink(event.getEiid(), theTimex.getTid(),
                    TLink.Type.IS_INCLUDED));
            }
  
            /*
             * // Look for a determiner. boolean isDefinite = false, isIndefinite
             * = false; String det = Ling.getDeterminer(sent.getDeps(),
             * event.getIndex()); if( det != null && det.equalsIgnoreCase("a") ) {
             * isIndefinite = true; System.out.println("INDEFINITE NOMINAL: " +
             * event); } if( det != null && det.equalsIgnoreCase("the") ) {
             * isDefinite = true; System.out.println("DEFINITE NOMINAL: " +
             * event); }
             * 
             * if( isDefinite ) { // proposed.add(new
             * EventTimeLink(event.getEiid(), doc.getDocstamp().get(0).getTid(),
             * TLink.Type.BEFORE)); } if( isIndefinite ) { // proposed.add(new
             * EventTimeLink(event.getEiid(), doc.getDocstamp().get(0).getTid(),
             * TLink.Type.BEFORE)); }
             */
  
            Pair<TextEvent, TypedDependency> pair = getGoverningEvent(sent,
                event);
            if (pair != null) {
              TextEvent eventGov = pair.first();
              String reln = pair.second().reln().toString();
              // System.out.println(sent.sentence());
              // System.out.println("Found governor for nominal: " + eventGov + "
              // over " + event);
  
              // High precision. Very low recall.
              if (reln.equalsIgnoreCase("prep_during")
                  || reln.equalsIgnoreCase("prep_while"))
                proposed.add(new EventEventLink(eventGov.getEiid(),
                    event.getEiid(), TLink.Type.IS_INCLUDED));
              if (reln.equalsIgnoreCase("prep_before"))
                proposed.add(new EventEventLink(eventGov.getEiid(),
                    event.getEiid(), TLink.Type.BEFORE));
              if (reln.equalsIgnoreCase("prep_after")
                  || reln.equalsIgnoreCase("prep_since"))
                proposed.add(new EventEventLink(eventGov.getEiid(),
                    event.getEiid(), TLink.Type.AFTER));
  
              // if( eventGov.getTense() == TextEvent.Tense.PAST )
              // proposed.add(new EventEventLink(eventGov.getEiid(),
              // event.getEiid(), TLink.Type.BEFORE));
              // if( eventGov.getTheClass() == TextEvent.Class.ASPECTUAL )
              // proposed.add(new EventEventLink(eventGov.getEiid(),
              // event.getEiid(), TLink.Type.IS_INCLUDED));
              // else if( eventGov.getTheClass() == TextEvent.Class.REPORTING )
              // proposed.add(new EventEventLink(eventGov.getEiid(),
              // event.getEiid(), TLink.Type.AFTER));
              // else
              // proposed.add(new EventEventLink(eventGov.getEiid(),
              // event.getEiid(), TLink.Type.VAGUE));
            }
          }
        }
  
        // Rules for Past tense, or Reporting verbs. I can't get any traction with
        // these...
        // for( int ii = 0; ii < events.size(); ii++ ) {
        // TextEvent event = events.get(ii);
        // for( int jj = ii+1; jj < events.size(); jj++ ) {
        // TextEvent event2 = events.get(jj);
        // if( event2.getTheClass() == TextEvent.Class.REPORTING ) {//if(
        // event2.getString().equalsIgnoreCase("said") ) {
        // if( event.getTense() == TextEvent.Tense.PAST && event.getTheClass() !=
        // TextEvent.Class.REPORTING ) {
        // proposed.add(new EventEventLink(event.getEiid(), event2.getEiid(),
        // TLink.Type.BEFORE));
        // }
        // }
        // }
        // }
  
      }
      // System.out.println("PROPOSED: " + proposed);
      return proposed;
    }
  
    /**
     * Look through the typed dependencies for cases where the event dominates a
     * Timex.
     * 
     * @param sent
     * @param event
     * @return The timex that the given event dominates.
     */
    private Pair<Timex, TypedDependency> getAttachedTimex(SieveSentence sent,
        TextEvent event) {
      List<Timex> timexes = sent.timexes();
      Map<Integer, Timex> positionToTimex = new HashMap<Integer, Timex>();
      for (Timex timex : timexes)
        for (int xx = timex.getTokenOffset(); xx < timex.getTokenOffset()
            + timex.getTokenLength(); xx++)
          positionToTimex.put(xx, timex);
  
      for (TypedDependency dep : sent.getDeps()) {
        if (dep.gov().index() == event.getIndex()) {
          Timex matchedTimex = positionToTimex.get(dep.dep().index());
          if (matchedTimex != null)
            return new Pair<Timex, TypedDependency>(matchedTimex, dep);
        }
      }
  
      return null;
    }
  
    private Pair<TextEvent, TypedDependency> getGoverningEvent(SieveSentence sent,
        TextEvent event) {
      List<TypedDependency> deps = sent.getDeps();
      for (TypedDependency dep : deps) {
        if (dep.dep().index() == event.getIndex()) {
          int govindex = dep.gov().index();
          for (TextEvent ee : sent.events())
            if (ee.getIndex() == govindex)
              return new Pair<TextEvent, TypedDependency>(ee, dep);
        }
      }
      return null;
    }
  
    /**
     * No training. Just rule-based.
     */
    public void train(SieveDocuments trainingInfo) {
      // no training
    }
  
  }
  