code: package caevo.sieves;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  
  import caevo.SieveDocument;
  import caevo.SieveDocuments;
  import caevo.TextEvent;
  import caevo.TextEventPattern;
  import caevo.Timex;
  import caevo.tlink.EventTimeLink;
  import caevo.tlink.TLink;
  
  /**
   * Order document creation time with events by considering tenses, aspects, and
   * classes
   * 
   * FIXME: More rule experimentation is needed. They might be improved to some
   * extent by considering attributes beyond just tense/class/aspect. Also:
   * "INFINITIVE" often is in the future (e.g. "is going to X"), but this is not
   * always the case (e.g. "was going to X").
   * 
   * The TextEventPatterns are a little confusing when rules start to overlap in
   * what they match. Be careful not to clobber a more precise rule that you
   * already added.
   *
   * Current Results (training): p=0.68 152 of 225 Non-VAGUE: p=0.80 152 of 189
   *
   * @author Bill McDowell
   * @author chambers
   */
  public class EventCreationTimeSieve implements Sieve {
    private HashMap<TextEventPattern, TLink.Type> tenseRules;
  
    public EventCreationTimeSieve() {
      /*
       * Rules map attributes of events to the TLink.Type of the link from
       * document creation time to the event
       * 
       * Rules are represented as TextEventPatterns so they can easily be extended
       * to include attributes other than tense in the future
       * 
       */
      this.tenseRules = new HashMap<TextEventPattern, TLink.Type>();
  
      // p=0.62 31 of 50 Non-VAGUE: p=0.91 31 of 34
      for (TextEvent.Class type : TextEvent.Class.values())
        this.tenseRules.put(new TextEventPattern(type, TextEvent.Tense.PRESENT,
            TextEvent.Aspect.PERFECTIVE), TLink.Type.BEFORE);
  
      // p=1.00 8 of 8 Non-VAGUE: p=1.00 8 of 8
      for (TextEvent.Class type : TextEvent.Class.values())
        this.tenseRules.put(new TextEventPattern(type, TextEvent.Tense.PAST,
            TextEvent.Aspect.PERFECTIVE), TLink.Type.BEFORE);
  
      // p=0.77 27 of 35 Non-VAGUE: p=0.93 27 of 29
      for (TextEvent.Aspect type : TextEvent.Aspect.values())
        this.tenseRules.put(new TextEventPattern(TextEvent.Class.REPORTING,
            TextEvent.Tense.PAST, type), TLink.Type.IS_INCLUDED);
  
      for (TextEvent.Class ctype : TextEvent.Class.values())
        for (TextEvent.Aspect atype : TextEvent.Aspect.values()) {
          if (ctype != TextEvent.Class.REPORTING) {
            this.tenseRules.put(
                new TextEventPattern(ctype, TextEvent.Tense.PAST, atype),
                TLink.Type.BEFORE);
            // this.tenseRules.put(new TextEventPattern(ctype,
            // TextEvent.Tense.INFINITIVE, atype), TLink.Type.AFTER); // good, but
            // not as good
            // this.tenseRules.put(new TextEventPattern(ctype,
            // TextEvent.Tense.PASTPART, atype), TLink.Type.BEFORE); // good, but
            // not as good
          }
        }
  
      // These general INCLUDED-type rules don't work. Many should be vague.
      // this.tenseRules.put(new TextEventPattern(null, TextEvent.Tense.FUTURE,
      // null), TLink.Type.AFTER);
      // this.tenseRules.put(new TextEventPattern(null, TextEvent.Tense.PRESENT,
      // null), TLink.Type.IS_INCLUDED);
      // this.tenseRules.put(new TextEventPattern(null, TextEvent.Tense.PRESPART,
      // null), TLink.Type.IS_INCLUDED);
      // this.tenseRules.put(new TextEventPattern(null, TextEvent.Tense.NONE,
      // null), TLink.Type.IS_INCLUDED);
    }
  
    public List<TLink> annotate(SieveDocument doc, List<TLink> currentTLinks) {
      List<TLink> proposed = new ArrayList<TLink>();
  
      if (doc.getDocstamp() == null || doc.getDocstamp().isEmpty())
        return proposed;
  
      Timex creationTime = doc.getDocstamp().get(0);
      List<TextEvent> allEvents = doc.getEvents();
  
      TextEventPattern eventPattern = new TextEventPattern();
      for (TextEvent event : allEvents) {
        eventPattern.setFromCanonicalEvent(event, true, true, true);
        if (this.tenseRules.containsKey(eventPattern)) {
          proposed.add(new EventTimeLink(event.getEiid(), creationTime.getTid(),
              this.tenseRules.get(eventPattern)));
        }
  
        // BASELINES for DCT links?
        // BEFORE: p=0.36 229 of 629
        // VAGUE: p=0.29 184 of 629
        // IS_INCLUDED: p=0.15 95 of 629
        // proposed.add(new EventTimeLink(event.getEiid(), creationTime.getTid(),
        // TLink.Type.IS_INCLUDED));
      }
  
      return proposed;
    }
  
    /**
     * No training. Just rule-based.
     */
    public void train(SieveDocuments trainingInfo) {
      // no training
    }
  
  }