ctakes-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From seanfi...@apache.org
Subject svn commit: r1660963 [5/19] - in /ctakes/sandbox/timelanes: META-INF/ edu/ edu/mayo/ edu/mayo/bmi/ edu/mayo/bmi/annotation/ edu/mayo/bmi/annotation/knowtator/ org/ org/chboston/ org/chboston/cnlp/ org/chboston/cnlp/anafora/ org/chboston/cnlp/anafora/an...
Date Thu, 19 Feb 2015 18:06:17 GMT
Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/DefaultAnnotation.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/DefaultAnnotation.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/DefaultAnnotation.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/DefaultAnnotation.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,386 @@
+package org.chboston.cnlp.nlp.annotation.annotation;
+
+import net.jcip.annotations.Immutable;
+import org.chboston.cnlp.nlp.annotation.attribute.*;
+import org.chboston.cnlp.nlp.annotation.classtype.ClassType;
+import org.chboston.cnlp.nlp.annotation.textspan.DefaultDiscontiguousTextSpan;
+import org.chboston.cnlp.nlp.annotation.textspan.DefaultTextSpan;
+import org.chboston.cnlp.nlp.annotation.textspan.DiscontiguousTextSpan;
+import org.chboston.cnlp.nlp.annotation.textspan.TextSpan;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Partial implementation of an Annotation
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/8/12
+ */
+@Immutable
+final public class DefaultAnnotation implements Annotation {
+
+   static private final String UNKNOWN_ANNOTATOR = "Unknown Annotator";
+   static private final Map<AttributeType, Attribute> EMPTY_ATTRIBUTES
+         = Collections.unmodifiableMap( new HashMap<AttributeType, Attribute>( 0 ) );
+   static private final Pattern SPACE_PATTERN = Pattern.compile( "\\s\\s\\s+" );
+   static private final Pattern DOT_PATTERN = Pattern.compile( "..." );
+
+   private final TextSpan _textSpan;
+   private final String _spannedText;
+   private final String _spannedTextRepresentation;
+   private final ClassType _classType;
+   // Keys are all stored and fetched as uppercase, but values are stored with case intact
+   private final Map<AttributeType, Attribute> _attributeMap;
+   private final int _hashcode;
+
+
+   static private String getSpannedText( final TextSpan textSpan, final String text ) {
+      if ( text.length() == textSpan.getLength() ) {
+         return text;
+      }
+      if ( textSpan instanceof DiscontiguousTextSpan ) {
+         final DiscontiguousTextSpan multipleSpan = (DiscontiguousTextSpan)textSpan;
+         final int spanCount = multipleSpan.getTextSpanCount();
+         if ( spanCount == 1 ) {
+            return getSpannedText( ((DiscontiguousTextSpan)textSpan).getTextSpan( 0 ), text );
+         }
+         if ( spanCount == 2 ) {
+            return expandText( multipleSpan.getTextSpan( 0 ), multipleSpan.getTextSpan( 1 ), text );
+         }
+         final TextSpan textSpan1 = ((DiscontiguousTextSpan)textSpan).getTextSpan( 0 );
+         final TextSpan[] subTextSpans = new TextSpan[ spanCount - 1 ];
+         for ( int i = 1; i < spanCount; i++ ) {
+            subTextSpans[ i - 1 ] = ((DiscontiguousTextSpan)textSpan).getTextSpan( i );
+         }
+         final TextSpan multiSubSpan = new DefaultDiscontiguousTextSpan( subTextSpans );
+         return expandText( textSpan1, multiSubSpan, text );
+      }
+      if ( text.length() > textSpan.getLength() ) {
+//         final String trimmed = text.replaceAll( "...", "   " ).trim();
+         final String trimmed = DOT_PATTERN.matcher( text ).replaceAll( "   " ).trim();
+         if ( text.length() > trimmed.length() ) {
+            return getSpannedText( textSpan, trimmed );
+         }
+         return text.substring( 0, textSpan.getLength() );
+      }
+      return expandText( textSpan, text, "" );
+   }
+
+   static private String expandText( final TextSpan textSpan1, final TextSpan textSpan2, final String text ) {
+      final String text1 = text.substring( 0, textSpan1.getLength() );
+      int midIndex = text.length() - textSpan2.getLength();
+      if ( midIndex < 0 ) {
+         // hopefully this doesn't happen too frequently - it indicates poorly formed text spans
+         midIndex = textSpan1.getLength() - 1;
+      }
+      final String text2 = getSpannedText( textSpan2, text.substring( midIndex ) );
+      return expandText( textSpan1, textSpan2, text1, text2 );
+   }
+
+   static private String expandText( final TextSpan textSpan, final String text1, final String text2 ) {
+      final char[] chars = new char[ textSpan.getLength() ];
+      Arrays.fill( chars, ' ' );
+      text1.getChars( 0, text1.length(), chars, 0 );
+      text2.getChars( 0, text2.length(), chars, chars.length - text2.length() );
+      return String.valueOf( chars );
+   }
+
+   static public String expandText( final TextSpan textSpan1, final TextSpan textSpan2, final String text1,
+                                    final String text2 ) {
+      final int startIndex = Math.min( textSpan1.getStartIndex(), textSpan2.getStartIndex() );
+      final int endIndex = Math.max( textSpan1.getEndIndex(), textSpan2.getEndIndex() );
+      final TextSpan jointTextSpan = new DefaultTextSpan( startIndex, endIndex );
+      if ( textSpan1.getStartIndex() <= textSpan2.getStartIndex() ) {
+         final int targetIndex = textSpan2.getStartIndex() - textSpan1.getStartIndex();
+         return expandText( jointTextSpan, text1, text2, targetIndex );
+      }
+      final int targetIndex = textSpan1.getStartIndex() - textSpan2.getStartIndex();
+      return expandText( jointTextSpan, text2, text1, targetIndex );
+   }
+
+   static private String expandText( final TextSpan textSpan, final String text1, final String text2,
+                                     final int targetIndex ) {
+      final char[] chars = new char[ textSpan.getLength() ];
+      Arrays.fill( chars, ' ' );
+      text1.getChars( 0, text1.length(), chars, 0 );
+
+      text2.getChars( 0, text2.length(), chars, targetIndex );
+      return String.valueOf( chars );
+   }
+
+   /**
+    * @param textSpan    the character-indexed textSpan of this annotation
+    * @param spannedText the text within this annotation's textSpan
+    * @param classType   class type of this annotation
+    * @param attributes  attributes of this annotation
+    */
+   public DefaultAnnotation( final TextSpan textSpan, final String spannedText, final ClassType classType,
+                             final Attribute... attributes ) {
+      _textSpan = textSpan;
+      _spannedText = getSpannedText( textSpan, spannedText );
+      _classType = classType;
+      if ( attributes.length > 0 ) {
+         _attributeMap = new HashMap<>( attributes.length );
+         for ( Attribute attribute : attributes ) {
+            _attributeMap.put( attribute.getAttributeType(), attribute );
+         }
+      } else {
+         _attributeMap = EMPTY_ATTRIBUTES;
+      }
+      _spannedTextRepresentation = createSpannedTextRepresentation();
+      int bits = _textSpan.hashCode();
+      bits += 3 * _classType.hashCode();
+//      bits += 5 * _spannedTextRepresentation.hashCode();
+      bits += 7 * _attributeMap.hashCode();
+      _hashcode = bits;
+   }
+
+   /**
+    * @param textSpan      the character-indexed textSpan of this annotation
+    * @param spannedText   the text within this annotation's textSpan
+    * @param classType     class type of this annotation
+    * @param annotatorName annotator that marked this annotation
+    * @param attributes    attributes of this annotation
+    */
+   @Deprecated
+   public DefaultAnnotation( final TextSpan textSpan, final String spannedText, final ClassType classType,
+                             final String annotatorName, final Attribute... attributes ) {
+      _textSpan = textSpan;
+      _spannedText = getSpannedText( textSpan, spannedText );
+      _classType = classType;
+      final String normalAnnotatorName = getNormalizedAnnotatorName( annotatorName );
+      _attributeMap = new HashMap<>( attributes.length + 1 );
+      for ( Attribute attribute : attributes ) {
+         _attributeMap.put( attribute.getAttributeType(), attribute );
+      }
+      new DefaultAttribute( DefinedAttributeType.CREATOR, normalAnnotatorName );
+      _spannedTextRepresentation = createSpannedTextRepresentation();
+      int bits = _textSpan.hashCode();
+      bits += 3 * _classType.hashCode();
+      bits += 5 * _spannedTextRepresentation.hashCode();
+      _hashcode = bits;
+   }
+
+   private String createSpannedTextRepresentation() {
+      // replace excessive whitespace with ellipses
+      return '[' + SPACE_PATTERN.matcher( getSpannedText() ).replaceAll( " ... " ).trim().toLowerCase() + ']';
+
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public TextSpan getTextSpan() {
+      return _textSpan;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getSpannedText() {
+      return _spannedText;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getSpannedTextRepresentation() {
+      return _spannedTextRepresentation;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public ClassType getClassType() {
+      return _classType;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean isClassType( final ClassType classType ) {
+      return _classType.equals( classType );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   @Deprecated
+   public List<String> getAttributeNames() {
+      final List<String> names = new ArrayList<>( _attributeMap.size() );
+      for ( AttributeType attributeType : _attributeMap.keySet() ) {
+         names.add( attributeType.getName() );
+      }
+      return names;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   @Deprecated
+   public Attribute getAttribute( final String key ) {
+      return _attributeMap.get( AttributeTypeFactory.getAttributeForName( key ) );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Attribute getAttribute( final AttributeType attributeType ) {
+      return _attributeMap.get( attributeType );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Collection<AttributeType> getAttributeTypes() {
+      return Collections.unmodifiableCollection( _attributeMap.keySet() );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Collection<Attribute> getAttributes() {
+      return Collections.unmodifiableCollection( _attributeMap.values() );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean hasAttribute( final String key ) {
+      for ( AttributeType attributeType : _attributeMap.keySet() ) {
+         if ( key.equals( attributeType.getName() ) ) {
+            return true;
+         }
+      }
+      return false;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean hasAttribute( final AttributeType attributeType ) {
+      return _attributeMap.containsKey( attributeType );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getAttributeValue( final String key ) {
+      for ( Attribute attribute : _attributeMap.values() ) {
+         if ( attribute.getName().equals( key ) ) {
+            return attribute.getValue();
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getAttributeValue( final AttributeType attributeType ) {
+      final Attribute attribute = _attributeMap.get( attributeType );
+      if ( attribute != null ) {
+         return attribute.getValue();
+      }
+      return null;
+   }
+
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   @Deprecated
+   public String getAnnotatorName() {
+      final Attribute annotator = getAttribute( DefinedAttributeType.CREATOR.getName() );
+      if ( annotator != null ) {
+         return annotator.getValue();
+      }
+      return UNKNOWN_ANNOTATOR;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   @Deprecated
+   public boolean areValuesEqual( final Annotation annotation ) {
+      if ( !annotation.getTextSpan().equals( _textSpan )
+           || !annotation.getSpannedTextRepresentation().equals( getSpannedTextRepresentation() )
+           || !annotation.getClassType().equals( _classType ) ) {
+         return false;
+      }
+      final Collection<String> annotationAttributeNames = annotation.getAttributeNames();
+      if ( annotationAttributeNames.size() != _attributeMap.size() ) {
+         return false;
+      }
+      for ( Attribute attribute : _attributeMap.values() ) {
+         if ( !attribute.equals( annotation.getAttribute( attribute.getAttributeType() ) ) ) {
+            return false;
+         }
+      }
+      return true;
+   }
+
+   /**
+    * @return ""[spanned text]" at Entity Span: [startIndex]-[endIndex] is a [classtype type]"
+    */
+   @Override
+   public String toString() {
+      return "\"" + getSpannedTextRepresentation() + "\" at " + _textSpan.toString()
+             + " is a " + getClassType() + " marked by "
+             + getAnnotatorName();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals( final Object object ) {
+      if ( !(object instanceof Annotation) ) {
+         return false;
+      }
+      final Annotation annotation = (Annotation)object;
+//      return annotation.getAnnotatorName().equals( _annotatorName ) && areValuesEqual( annotation );
+      return areValuesEqual( annotation );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return _hashcode;
+   }
+
+
+   /**
+    * @param annotatorName name of the annotator that marked this annotation
+    * @return the annotator name stripped of any commas (put there by Knowtator?)
+    */
+   static private String getNormalizedAnnotatorName( final String annotatorName ) {
+      if ( annotatorName == null ) {
+         return UNKNOWN_ANNOTATOR;
+      }
+      if ( annotatorName.endsWith( " ," ) || annotatorName.endsWith( ", " ) ) {
+         return annotatorName.substring( 0, annotatorName.length() - 2 );
+      }
+      return annotatorName;
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStore.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStore.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStore.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStore.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,63 @@
+package org.chboston.cnlp.nlp.annotation.annotation.store;
+
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceChain;
+import org.chboston.cnlp.nlp.annotation.coreference.EntityIdCollection;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+
+import java.util.List;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/22/12
+ */
+public interface AnnotationStore {
+
+   /**
+    * @return Collection of Annotation Named Entities
+    */
+   public List<Entity> getNamedEntities();
+
+   /**
+    * @return Collection of Annotation Events
+    */
+   public List<Entity> getEvents();
+
+   /**
+    * @return Collection of Annotation Timex3's - specifically defined times; e.g. 3:00 pm
+    */
+   public List<Entity> getTimes();
+
+   /**
+    * @return Collection of Annotation UMLS Relations
+    */
+   public List<Relation> getUmlsRelations();
+
+   /**
+    * @return Collection of Annotation Temporal Relations
+    */
+   public List<Relation> getTimeRelations();
+
+   /**
+    * @return collection of coreferenced entity chains
+    */
+   public List<CoreferenceChain> getCoreferenceChains();
+
+   /**
+    * @return total number of words in the annotated documents, or -1 if unknown
+    */
+   public int getWordCount();
+
+   /**
+    * @return the full text to which the annotation collection applies
+    */
+   public String getDocumentText();
+
+   /**
+    * @return a EntityIdCollection that has aggregated all non-unique entities into CoreferenceChains
+    */
+   public EntityIdCollection getReferenceCollection();
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStoreFactory.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStoreFactory.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStoreFactory.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/AnnotationStoreFactory.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,217 @@
+package org.chboston.cnlp.nlp.annotation.annotation.store;
+
+import org.chboston.cnlp.anafora.annotation.parser.AnaforaXmlParser;
+import org.chboston.cnlp.xmi.parser.UimaXmiParser;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceChain;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceFactory;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.parser.AnnotationsParser;
+import org.chboston.cnlp.nlp.annotation.textspan.TextSpan;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/26/14
+ */
+final public class AnnotationStoreFactory {
+
+   private AnnotationStoreFactory() {
+   }
+
+
+   static private final String NONE_SELECTED = "None Selected";
+   static private final AnnotationStore EMPTY_COLLECTION = new ImmutableAnnotationStore.AnnoteCollectBuilder().build();
+
+   static public AnnotationStore createAnnotationCollection( final String documentPath ) {
+      if ( documentPath.endsWith( ".xmi" ) ) {
+         return createXmiAnnotationCollection( documentPath );
+      }
+      String documentName = documentPath;
+      final int lastDot = documentPath.lastIndexOf( '.' );
+      if ( lastDot > 0 ) {
+         documentName = documentPath.substring( 0, lastDot );
+      }
+      final String goldSuffix = ".gold.completed.xml";
+      final String coreferencePath = documentName + ".Coreference" + goldSuffix;
+      //      final String eventTimePath = documentName + ".Temporal-Entity" + goldSuffix;
+      String temporalPath = documentName + ".Temporal-Relation" + goldSuffix;
+      if ( !new File( temporalPath ).exists() ) {
+         temporalPath = documentName + ".Temporal-Relations" + goldSuffix;
+      }
+
+      final String umlsEntityPath = documentName + ".UMLS-Entity" + goldSuffix;
+      return createAnnotationCollection( temporalPath, umlsEntityPath, coreferencePath, documentPath, EMPTY_COLLECTION );
+   }
+
+   static public AnnotationStore createAnnotationCollection2( final File documentDir, final File documentFile ) {
+      String documentName = documentFile.getName();
+      final int lastDot = documentName.lastIndexOf( '.' );
+      if ( lastDot > 0 ) {
+         documentName = documentName.substring( 0, lastDot );
+      }
+      final String goldSuffix = ".gold.completed.xml";
+//      final String eventTimePath = documentName + ".Temporal-Entity" + goldSuffix;
+      File temporalFile = new File( documentDir, documentName + ".Temporal-Relation" + goldSuffix );
+      if ( !temporalFile.exists() ) {
+         temporalFile = new File( documentDir, documentName + ".Temporal-Relations" + goldSuffix );
+      }
+      if ( !temporalFile.exists() ) {
+         return EMPTY_COLLECTION;
+      }
+      final String temporalPath = temporalFile.getPath();
+      final File coreferenceFile = new File( documentDir, documentName + ".Coreference" + goldSuffix );
+      String coreferencePath = NONE_SELECTED;
+      if ( coreferenceFile.exists() ) {
+         coreferencePath = coreferenceFile.getPath();
+      }
+      final File umlsEntityFile = new File( documentDir, documentName + ".UMLS-Entity" + goldSuffix );
+      String umlsEntityPath = NONE_SELECTED;
+      if ( umlsEntityFile.exists() ) {
+         umlsEntityPath = umlsEntityFile.getPath();
+      }
+      return createAnnotationCollection( temporalPath, umlsEntityPath, coreferencePath,
+            documentFile.getPath(), EMPTY_COLLECTION );
+   }
+
+
+   static public AnnotationStore createAnnotationCollection2( final String documentPath, String documentName ) {
+      final int lastDot = documentName.lastIndexOf( '.' );
+      if ( lastDot > 0 ) {
+         documentName = documentName.substring( 0, lastDot );
+      }
+      final String goldSuffix = ".gold.completed.xml";
+//      final String eventTimePath = documentName + ".Temporal-Entity" + goldSuffix;
+      String temporalPath = documentPath + "/" + documentName + ".Temporal-Relation" + goldSuffix;
+      if ( !new File( temporalPath ).exists() ) {
+         temporalPath = documentPath + "/" + documentName + ".Temporal-Relations" + goldSuffix;
+      }
+      if ( !new File( temporalPath ).exists() ) {
+         return EMPTY_COLLECTION;
+      }
+      String coreferencePath = documentPath + "/" + documentName + ".Coreference" + goldSuffix;
+      if ( !new File( coreferencePath ).exists() ) {
+         coreferencePath = NONE_SELECTED;
+      }
+      String umlsEntityPath = documentPath + "/" + documentName + ".UMLS-Entity" + goldSuffix;
+      if ( !new File( umlsEntityPath ).exists() ) {
+         umlsEntityPath = NONE_SELECTED;
+      }
+      return createAnnotationCollection( temporalPath, umlsEntityPath, coreferencePath,
+            documentPath + "/" + documentName, EMPTY_COLLECTION );
+   }
+
+   static public AnnotationStore createAnnotationCollection( final String temporalPath, final String umlsPath,
+                                                             final String corefPath, final String documentPath,
+                                                             final AnnotationStore lastAnnotationStore ) {
+      final AnnotationStore thymeAnnotationStore
+            = temporalPath.equals( NONE_SELECTED ) ? EMPTY_COLLECTION
+                                                   : getAnnotationCollection( temporalPath, documentPath );
+      final AnnotationStore umlsAnnotationStore
+            = umlsPath.equals( NONE_SELECTED ) ? EMPTY_COLLECTION : getAnnotationCollection( umlsPath, documentPath );
+      AnnotationStore coreferenceCollection = EMPTY_COLLECTION;
+      if ( !corefPath.equals( NONE_SELECTED ) ) {
+         coreferenceCollection = getAnnotationCollection( corefPath, documentPath );
+         final List<CoreferenceChain> coreferenceChains = coreferenceCollection.getCoreferenceChains();
+         if ( coreferenceChains == null || coreferenceChains.isEmpty() ) {
+            coreferenceCollection = getCoreferenceCollection( corefPath,
+                  umlsAnnotationStore.getNamedEntities(),
+                  thymeAnnotationStore.getEvents(),
+                  thymeAnnotationStore.getTimes(),
+                  documentPath );
+         }
+      }
+      final AnnotationStore documentAnnotationStore
+            = documentPath.equals( NONE_SELECTED ) ? EMPTY_COLLECTION : getDocumentAnnotationCollection( documentPath );
+
+      final java.util.List<AnnotationStore> annotationStoreList = new ArrayList<>( 2 );
+      annotationStoreList.add( thymeAnnotationStore );
+      annotationStoreList.add( umlsAnnotationStore );
+      annotationStoreList.add( coreferenceCollection );
+      annotationStoreList.add( documentAnnotationStore );
+      if ( lastAnnotationStore != null && !lastAnnotationStore.equals( EMPTY_COLLECTION ) ) {
+         annotationStoreList.add( lastAnnotationStore );
+      }
+      return new ImmutableAnnotationStore.AnnoteCollectMerger().all( annotationStoreList ).build();
+   }
+
+   static private AnnotationStore getAnnotationCollection( final String filePath, final String docFilePath ) {
+      if ( !new File( filePath ).exists() ) {
+         return EMPTY_COLLECTION;
+      }
+      final AnnotationsParser parser = getParser( filePath, docFilePath );
+      if ( parser == null ) {
+         return EMPTY_COLLECTION;
+      }
+      parser.parseFile( filePath );
+      return parser.getAnnotationStore();
+   }
+
+
+   static private AnnotationStore getCoreferenceCollection( final String corefTextSpansPath,
+                                                            final Collection<Entity> entityCollection,
+                                                            final Collection<Entity> eventCollection,
+                                                            final Collection<Entity> timeCollection,
+                                                            final String docFilePath ) {
+      final AnnotationsParser parser = getParser( corefTextSpansPath, docFilePath );
+      parser.setDocumentTextFile( docFilePath );
+      final List<Collection<TextSpan>> coreferenceTextSpans = parser.parseCoreferenceTextSpans( corefTextSpansPath );
+      final java.util.List<CoreferenceChain> coreferenceChains
+            = CoreferenceFactory.createCoreferenceChains( coreferenceTextSpans, entityCollection,
+            eventCollection, timeCollection );
+      return new ImmutableAnnotationStore.AnnoteCollectBuilder().coreferenceChains( coreferenceChains ).build();
+   }
+
+
+   static private AnnotationsParser getParser( final String dataFilePath, final String docFilePath ) {
+//      if ( AnaforaXmlParser.canParse( dataFilePath ) ) {
+      final AnnotationsParser parser = new AnaforaXmlParser();
+      parser.setDocumentTextFile( docFilePath );
+      return parser;
+//      } else if ( KnowtatorXmlParser.canParse( dataFilePath ) ) {
+//         return new KnowtatorXmlParser();
+//               } else if ( docFilePath.endsWith( ".pprj" ) ) {
+//                  return getPprjParser( dataFilePath, docFilePath );
+//      }
+//      return null;
+   }
+
+   static private AnnotationStore getDocumentAnnotationCollection( final String filePath ) {
+      final File textFile = new File( filePath );
+      if ( !textFile.canRead() ) {
+         return EMPTY_COLLECTION;
+      }
+      final StringBuilder sb = new StringBuilder();
+      try ( final BufferedReader reader = new BufferedReader( new FileReader( textFile ) ) ) {
+         final char[] buffer = new char[ 8192 ];
+         int length = reader.read( buffer, 0, buffer.length );
+         while ( length >= 0 ) {
+            sb.append( buffer, 0, length );
+            length = reader.read( buffer, 0, buffer.length );
+         }
+         reader.close();
+      } catch ( IOException ioE ) {
+         System.err.println( ioE.getMessage() );
+         return EMPTY_COLLECTION;
+      }
+      final ImmutableAnnotationStore.AnnoteCollectBuilder builder
+            = new ImmutableAnnotationStore.AnnoteCollectBuilder();
+      return builder.documentText( sb.toString() ).build();
+   }
+
+
+   static public AnnotationStore createXmiAnnotationCollection( final String xmiPath ) {
+      final AnnotationsParser parser = new UimaXmiParser();
+      parser.parseFile( xmiPath );
+      return parser.getAnnotationStore();
+   }
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/DefaultAnnotationStore.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/DefaultAnnotationStore.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/DefaultAnnotationStore.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/DefaultAnnotationStore.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,173 @@
+package org.chboston.cnlp.nlp.annotation.annotation.store;
+
+import net.jcip.annotations.Immutable;
+import org.chboston.cnlp.anafora.annotation.parser.AnaforaRelationSegregator;
+import org.chboston.cnlp.xmi.parser.XmiEntitySegregator;
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationSpanComparator;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceChain;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceFactory;
+import org.chboston.cnlp.nlp.annotation.coreference.EntityIdCollection;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+import org.chboston.cnlp.nlp.annotation.textspan.TextSpan;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * @author SPF , chip-nlp
+ * @version %I%
+ * @since 12/11/2014
+ */
+@Immutable
+final public class DefaultAnnotationStore implements AnnotationStore {
+
+   static private final Logger LOGGER = Logger.getLogger( "DefaultAnnotationStore" );
+
+   // This slows down this step, but on a bunch of adjudicated datasets all annotators are kept, which is bad
+   static private <T extends Annotation> List<T> createSortedList( final Iterable<T> annotations ) {
+      if ( annotations == null ) {
+         return Collections.emptyList();
+      }
+      final List<T> sortableList = new ArrayList<>();
+      for ( T annotation : annotations ) {
+         boolean store = true;
+         for ( T storedAnnotation : sortableList ) {
+            if ( storedAnnotation.areValuesEqual( annotation ) ) {
+               store = false;
+               break;
+            }
+         }
+         if ( store ) {
+            sortableList.add( annotation );
+         }
+      }
+      Collections.sort( sortableList, AnnotationSpanComparator.getInstance() );
+      return Collections.unmodifiableList( sortableList );
+   }
+
+
+   private final List<Entity> _entityList;
+   private final List<Entity> _eventList;
+   private final List<Entity> _timexList;
+
+   private final List<Relation> _umlsRelationList;
+   private final List<Relation> _timeRelationList;
+   private final List<CoreferenceChain> _coreferenceChainList;
+
+   private final int _wordCount;
+   private final String _documentText;
+
+   private final EntityIdCollection _entityIdCollection;
+
+
+   public DefaultAnnotationStore( final Collection<Entity> allEntities, final Collection<Relation> allRelations,
+                                  final String documentText ) {
+      this( XmiEntitySegregator.getNamedEntities( allEntities ),
+            XmiEntitySegregator.getEvents( allEntities ),
+            XmiEntitySegregator.getTimes( allEntities ),
+            AnaforaRelationSegregator.getUmlsRelations( allRelations ),
+            AnaforaRelationSegregator.getTemporalRelations( allRelations ),
+            null, documentText );
+   }
+
+   public DefaultAnnotationStore( final Collection<Entity> namedEntities, final Collection<Entity> events,
+                                  final Collection<Entity> times,
+                                  final Collection<Relation> umlsRelations, final Collection<Relation> timeRelations,
+                                  final Iterable<Collection<TextSpan>> textSpanChains,
+                                  final String documentText ) {
+      _entityList = createSortedList( namedEntities );
+      _eventList = createSortedList( events );
+      _timexList = createSortedList( times );
+      _umlsRelationList = createSortedList( umlsRelations );
+      _timeRelationList = createSortedList( timeRelations );
+      _coreferenceChainList = CoreferenceFactory.createCoreferenceChains( textSpanChains, namedEntities,
+            events, times );
+      int wordCount = -1;
+      if ( documentText != null && !documentText.isEmpty() ) {
+         wordCount = documentText.split( "\\s+" ).length;
+      }
+      _documentText = documentText;
+      _wordCount = wordCount;
+      _entityIdCollection = new EntityIdCollection( this );
+   }
+
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Entity> getNamedEntities() {
+      return _entityList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Entity> getEvents() {
+      return _eventList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Entity> getTimes() {
+      return _timexList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Relation> getUmlsRelations() {
+      return _umlsRelationList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Relation> getTimeRelations() {
+      return _timeRelationList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<CoreferenceChain> getCoreferenceChains() {
+      return _coreferenceChainList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int getWordCount() {
+      return _wordCount;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getDocumentText() {
+      return _documentText;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EntityIdCollection getReferenceCollection() {
+      return _entityIdCollection;
+   }
+
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/ImmutableAnnotationStore.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/ImmutableAnnotationStore.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/ImmutableAnnotationStore.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/annotation/store/ImmutableAnnotationStore.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,789 @@
+package org.chboston.cnlp.nlp.annotation.annotation.store;
+
+import net.jcip.annotations.Immutable;
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+import org.chboston.cnlp.nlp.annotation.annotation.AnnotationSpanComparator;
+import org.chboston.cnlp.nlp.annotation.classtype.TemporalClassType;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceChain;
+import org.chboston.cnlp.nlp.annotation.coreference.EntityIdCollection;
+import org.chboston.cnlp.nlp.annotation.entity.Entity;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+
+import javax.swing.*;
+import java.util.*;
+
+// TODO Refactor sorted and unsorted, add word count to setText()
+// TODO get rid of stupid AnnoteCollectBuilder
+
+/**
+ * Immutable collection of annotations
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/22/12
+ */
+@Immutable
+@Deprecated
+final public class ImmutableAnnotationStore implements AnnotationStore {
+   static private final String UNKNOWN = "Unknown";
+
+   // This slows down this step, but on a bunch of adjudicated datasets all annotators are kept, which is bad
+   static private <T extends Annotation> List<T> getSortedList( final List<T> annotations ) {
+      if ( annotations == null ) {
+         return Collections.emptyList();
+      }
+      final List<T> sortableList = new ArrayList<>();
+      for ( T annotation : annotations ) {
+         boolean store = true;
+         for ( T storedAnnotation : sortableList ) {
+            if ( storedAnnotation.areValuesEqual( annotation ) ) {
+               store = false;
+               break;
+            }
+         }
+         if ( store ) {
+            sortableList.add( annotation );
+         }
+      }
+//      final List<T> sortableList = new ArrayList<T>( annotations );
+      Collections.sort( sortableList, AnnotationSpanComparator.getInstance() );
+//      return Collections.unmodifiableList( sortableList );
+      return sortableList;
+   }
+
+   static abstract private class AbstractBuilder {
+      protected String __annotatorName = UNKNOWN;
+
+      protected List<Entity> __entityList = Collections.emptyList();
+      protected List<Entity> __eventList = Collections.emptyList();
+      protected List<Entity> __timexList = Collections.emptyList();
+
+      protected List<Relation> __umlsRelationList = Collections.emptyList();
+      protected List<Relation> __timeRelationList = Collections.emptyList();
+      protected List<CoreferenceChain> __coreferenceChainList = Collections.emptyList();
+      //      protected List<Collection<TextSpan>> __coreferenceTextSpans = Collections.emptyList();
+      protected int __wordCount = -1;
+      protected String __documentText = null;
+
+      public ImmutableAnnotationStore build() {
+         return new ImmutableAnnotationStore( this, false );
+      }
+   }
+
+   /**
+    * A Builder that can create a new AnnotationCollection.
+    * All Annotation Lists are sorted before storage.
+    * Sorting is done is because parsers can create/return annotations in different orders,
+    * and (for one thing) the AgreementEvaluator will return different equal matches depending upon
+    * the order of annotations as they are given to the Evaluator.  Though this DOES NOT CHANGE
+    * the actual returned results (numeric scores), it can confuse a reader trying to match agreed
+    * Annotation spans measured by evaluation based upon two different parsers working with the same annotations.
+    * For instance, Annotator 1 annotates [A B] while Annotator 2 annotates [A] and [B].  If one parser returns
+    * [A] before [B], then the (overlapping textspan) match is [A B] ~ [A], while if the other parser returns
+    * [B] before [A], then the (overlapping textspan) match is [A B] ~ [B].  This will not change the numeric scores.
+    */
+   static public class AnnoteCollectBuilder extends AbstractBuilder {
+      public AnnoteCollectBuilder annotator( final String annotatorName ) {
+         __annotatorName = annotatorName;
+         return this;
+      }
+
+      public AnnoteCollectBuilder entities( final List<Entity> entityList ) {
+         // Sometimes immutability can be a pain in the butt.  Can't sort an unmodifiable list,
+         // so create a copy, sort the copy, then store the copy (unmodifiable wrapped)
+         __entityList = getSortedList( entityList );
+         return this;
+      }
+
+      public AnnoteCollectBuilder events( final List<Entity> eventList ) {
+         __eventList = getSortedList( eventList );
+         return this;
+      }
+
+      public AnnoteCollectBuilder times( final List<Entity> timexList ) {
+         __timexList = getSortedList( timexList );
+         return this;
+      }
+
+      public AnnoteCollectBuilder relations( final List<Relation> umlsRelationList ) {
+         __umlsRelationList = getSortedList( umlsRelationList );
+         return this;
+      }
+
+      public AnnoteCollectBuilder timeRelations( final List<Relation> timeRelationList ) {
+         __timeRelationList = getSortedList( timeRelationList );
+         return this;
+      }
+
+      public AnnoteCollectBuilder coreferenceChains( final List<CoreferenceChain> coreferenceChainList ) {
+         __coreferenceChainList = getSortedList( coreferenceChainList );
+         return this;
+      }
+
+//      public AnnoteCollectBuilder coreferenceTextSpans( final List<Collection<TextSpan>> coreferenceTextSpans ) {
+//         __coreferenceTextSpans = coreferenceTextSpans;
+//         return this;
+//      }
+
+      public AnnoteCollectBuilder wordCount( final int wordCount ) {
+         __wordCount = wordCount;
+         return this;
+      }
+
+      public AnnoteCollectBuilder documentText( final String documentText ) {
+         __documentText = documentText;
+         return this;
+      }
+   }
+
+   /**
+    * A Builder that can create a new AnnotationCollection.
+    * Annotation Lists are NOT sorted before storage.
+    */
+   static public class UnSortedAnnoteCollectBuilder extends AbstractBuilder {
+      public UnSortedAnnoteCollectBuilder annotator( final String annotatorName ) {
+         __annotatorName = annotatorName;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder entities( final List<Entity> entityList ) {
+         // Sometimes immutability can be a pain in the butt.  Can't sort an unmodifiable list,
+         // so create a copy, sort the copy, then store the copy (unmodifiable wrapped)
+         __entityList = entityList;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder events( final List<Entity> eventList ) {
+         __eventList = eventList;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder times( final List<Entity> timexList ) {
+         __timexList = timexList;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder relations( final List<Relation> umlsRelationList ) {
+         __umlsRelationList = umlsRelationList;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder timeRelations( final List<Relation> timeRelationList ) {
+         __timeRelationList = timeRelationList;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder coreferenceChains( final List<CoreferenceChain> coreferenceChainList ) {
+         __coreferenceChainList = coreferenceChainList;
+         return this;
+      }
+
+//      public UnSortedAnnoteCollectBuilder coreferenceTextSpans( final List<Collection<TextSpan>> coreferenceTextSpans ) {
+//         __coreferenceTextSpans = coreferenceTextSpans;
+//         return this;
+//      }
+
+      public UnSortedAnnoteCollectBuilder wordCount( final int wordCount ) {
+         __wordCount = wordCount;
+         return this;
+      }
+
+      public UnSortedAnnoteCollectBuilder documentText( final String documentText ) {
+         __documentText = documentText;
+         return this;
+      }
+   }
+
+   /**
+    * A Builder that will merge AnnotationCollections
+    */
+   static public class AnnoteCollectMerger extends AbstractBuilder {
+      public AnnoteCollectMerger all( final List<AnnotationStore> collectionList ) {
+         final Set<String> annotators = new HashSet<>();
+         final List<Entity> entityList = new ArrayList<>();
+         final List<Entity> eventList = new ArrayList<>();
+         final List<Entity> timexList = new ArrayList<>();
+         final List<Relation> umlsRelationList = new ArrayList<>();
+         final List<Relation> timeRelationList = new ArrayList<>();
+         final List<CoreferenceChain> coreferenceChainList = new ArrayList<>();
+//         final List<Collection<TextSpan>> coreferenceTextSpans = new ArrayList<>();
+         __wordCount = 0;
+         __documentText = "";
+         for ( AnnotationStore collection : collectionList ) {
+//            final String annotator = collection.getAnnotatorName();
+//            if ( annotator != null && !annotator.isEmpty() ) {
+//               annotators.add( annotator );
+//            }
+            entityList.addAll( collection.getNamedEntities() );
+            eventList.addAll( collection.getEvents() );
+            timexList.addAll( collection.getTimes() );
+            umlsRelationList.addAll( collection.getUmlsRelations() );
+            timeRelationList.addAll( collection.getTimeRelations() );
+            coreferenceChainList.addAll( collection.getCoreferenceChains() );
+//            coreferenceTextSpans.addAll( collection.getCoreferenceTextSpans() );
+            if ( collection.getWordCount() <= 0 || __wordCount < 0 ) {
+               // If any collection doesn't have a word count, then the merged collection cannot
+               __wordCount = -1;
+            } else {
+               __wordCount += collection.getWordCount();
+            }
+            if ( collection.getDocumentText() == null || __documentText == null ) {
+               // If any collection doesn't have document text, then the merged collection cannot
+               // TODO - need a factory or better builder - this is commented for timeline vis loader,
+               // which reads 4 files until the cTakes input is ready
+//               __documentText = null;
+            } else {
+               if ( __documentText == null ) {
+                  __documentText = collection.getDocumentText();
+               } else if ( !__documentText.equals( collection.getDocumentText() ) ) {
+                  if ( !__documentText.isEmpty() ) {
+                     __documentText += "\r\n";
+                  }
+                  __documentText += collection.getDocumentText();
+               }
+            }
+         }
+         __entityList = getSortedList( entityList );
+         __eventList = getSortedList( eventList );
+         __timexList = getSortedList( timexList );
+         __umlsRelationList = getSortedList( umlsRelationList );
+         __timeRelationList = getSortedList( timeRelationList );
+         __coreferenceChainList = getSortedList( coreferenceChainList );
+//         __coreferenceTextSpans = coreferenceTextSpans;
+         final StringBuilder annotatorB = new StringBuilder();
+         for ( String name : annotators ) {
+            annotatorB.append( name ).append( ", " );
+         }
+         __annotatorName = annotatorB.toString();
+         return this;
+      }
+
+      public ImmutableAnnotationStore build() {
+         return new ImmutableAnnotationStore( this, true );
+      }
+   }
+
+   /**
+    * A Builder that will merge AnnotationCollections
+    */
+   static public class UnSortedAnnoteCollectMerger extends AbstractBuilder {
+      public UnSortedAnnoteCollectMerger all( final List<AnnotationStore> collectionList ) {
+         final Set<String> annotators = new HashSet<>();
+         final List<Entity> entityList = new ArrayList<>();
+         final List<Entity> eventList = new ArrayList<>();
+         final List<Entity> timexList = new ArrayList<>();
+         final List<Relation> umlsRelationList = new ArrayList<>();
+         final List<Relation> timeRelationList = new ArrayList<>();
+         final List<CoreferenceChain> coreferenceChainList = new ArrayList<>();
+//         final List<Collection<TextSpan>> coreferenceTextSpans = new ArrayList<>();
+         __wordCount = 0;
+         __documentText = "";
+         for ( AnnotationStore collection : collectionList ) {
+//            final String annotator = collection.getAnnotatorName();
+//            if ( annotator != null && !annotator.isEmpty() ) {
+//               annotators.add( annotator );
+//            }
+            entityList.addAll( collection.getNamedEntities() );
+            eventList.addAll( collection.getEvents() );
+            timexList.addAll( collection.getTimes() );
+            umlsRelationList.addAll( collection.getUmlsRelations() );
+            timeRelationList.addAll( collection.getTimeRelations() );
+            coreferenceChainList.addAll( collection.getCoreferenceChains() );
+//            coreferenceTextSpans.addAll( collection.getCoreferenceTextSpans() );
+            if ( collection.getWordCount() <= 0 || __wordCount < 0 ) {
+               // If any collection doesn't have a word count, then the merged collection cannot
+               __wordCount = -1;
+            } else {
+               __wordCount += collection.getWordCount();
+            }
+            if ( collection.getDocumentText() == null || __documentText == null ) {
+               // If any collection doesn't have document text, then the merged collection cannot
+               __documentText = null;
+            } else {
+               __documentText += "\r\n" + collection.getDocumentText();
+            }
+         }
+         __entityList = entityList;
+         __eventList = eventList;
+         __timexList = timexList;
+         __umlsRelationList = umlsRelationList;
+         __timeRelationList = timeRelationList;
+         __coreferenceChainList = coreferenceChainList;
+//         __coreferenceTextSpans = coreferenceTextSpans;
+         final StringBuilder annotatorB = new StringBuilder();
+         for ( String name : annotators ) {
+            annotatorB.append( name ).append( ", " );
+         }
+         __annotatorName = annotatorB.toString();
+         return this;
+      }
+
+      public ImmutableAnnotationStore build() {
+         return new ImmutableAnnotationStore( this, true );
+      }
+   }
+
+
+//   static private Collection<String> getAnnotatorNames( final List<? extends Annotation> ... annotationLists ) {
+//      final Collection<String> annotatorNames = new HashSet<String>( 1 );
+//      for ( List<? extends Annotation> annotationList : annotationLists ) {
+//         final Collection<String> annotationAnnotators = getAnnotatorNames( annotationList );
+//         if ( annotationAnnotators.size() > 1 ) {
+//            final String wantedAnnotator = getWantedAnnotator( annotationAnnotators );
+//            if ( wantedAnnotator.equals( ALL_ANNOTATORS ) ) {
+//               annotatorNames.addAll( annotationAnnotators );
+//            } else {
+//               annotatorNames.add( wantedAnnotator );
+//            }
+//         } else {
+//            annotatorNames.addAll( annotatorNames );
+//         }
+////         for ( Annotation annotation : annotationList ) {
+////            annotatorNames.add( annotation.getAnnotatorName() );
+////         }
+//      }
+//      return annotatorNames;
+//   }
+
+
+   static private Map<String, Collection<String>> getAnnotatorNames( final Collection<Entity> entities,
+                                                                     final Collection<Entity> events,
+                                                                     final Collection<Entity> times,
+                                                                     final Collection<Relation> umlsRelations,
+                                                                     final Collection<Relation> tlinks,
+                                                                     final Collection<CoreferenceChain> coreferences ) {
+      final Collection<String> entityAnnotators = getAnnotatorNames( entities );
+      final Collection<String> eventAnnotators = getAnnotatorNames( events );
+      final Collection<String> timexAnnotators = getAnnotatorNames( times );
+      final Collection<String> umlsRelationAnnotators = getAnnotatorNames( umlsRelations );
+      final Collection<String> tlinkAnnotators = getAnnotatorNames( tlinks );
+      final Collection<String> corefAnnotators = getAnnotatorNames( coreferences );
+      final Map<String, Collection<String>> annotatorNames = new HashMap<>( 6 );
+      annotatorNames.put( "NamedEntity", entityAnnotators );
+      annotatorNames.put( TemporalClassType.EVENT.getName(), eventAnnotators );
+      annotatorNames.put( TemporalClassType.TIMEX.getName(), timexAnnotators );
+      annotatorNames.put( Relation.class.getName(), umlsRelationAnnotators );
+      annotatorNames.put( TemporalClassType.TLINK.getName(), tlinkAnnotators );
+      annotatorNames.put( CoreferenceChain.class.getName(), corefAnnotators );
+      return annotatorNames;
+   }
+
+   static private <T extends Annotation> Collection<String> getAnnotatorNames( final Collection<T> annotationList ) {
+      if ( annotationList == null ) {
+         return Collections.emptySet();
+      }
+      final Collection<String> annotatorNames = new HashSet<>( 1 );
+      for ( Annotation annotation : annotationList ) {
+         annotatorNames.add( annotation.getAnnotatorName() );
+      }
+      return annotatorNames;
+   }
+
+   static private Map<String, Collection<String>> getConflictingAnnotations(
+         final Map<String, Collection<String>> annotatorNames ) {
+      // Map of annotator names to annotation types by that annotator
+      final Map<String, Collection<String>> conflicters = new HashMap<>();
+      for ( Map.Entry<String, Collection<String>> annotatorNameEntry : annotatorNames.entrySet() ) {
+         for ( String annotatorName : annotatorNameEntry.getValue() ) {
+            Collection<String> annotationTypes = conflicters.get( annotatorName );
+            if ( annotationTypes == null ) {
+               annotationTypes = new HashSet<>( 1 );
+               conflicters.put( annotatorName, annotationTypes );
+            }
+            annotationTypes.add( annotatorNameEntry.getKey() );
+         }
+      }
+      return conflicters;
+   }
+
+   static private <T extends Annotation> List<T> filterAnnotators( final List<T> annotations,
+                                                                   final String annotatorName ) {
+      final List<T> filteredAnnotations = new ArrayList<>();
+//      final List<T> unfilteredAnnotations = new ArrayList<T>();
+      if ( annotations.isEmpty() || annotatorName == null ) {
+         filteredAnnotations.addAll( annotations );
+      } else if ( annotatorName.equals( ALL_ANNOTATORS ) ) {
+         filteredAnnotations.addAll( annotations );
+      } else {
+         for ( T annotation : annotations ) {
+            if ( annotation.getAnnotatorName().equals( annotatorName ) ) {
+               filteredAnnotations.add( annotation );
+//            } else {
+//               unfilteredAnnotations.add( annotation );
+            }
+         }
+      }
+//      final List<Annotation> repeatAnnotations = new ArrayList<Annotation>();
+//      final Annotation[] unfiltered = unfilteredAnnotations.toArray( new Annotation[unfilteredAnnotations.size()] );
+//      for ( int i=0; i<unfiltered.length; i++ ) {
+//         for ( int j=0; j<i; j++ ) {
+//            if ( unfiltered[i].getTextSpan().equals( unfiltered[j].getTextSpan() )
+//                  && unfiltered[i].getClassType().equals( unfiltered[j].getClassType() ) ) {
+//               repeatAnnotations.add( unfiltered[i] );
+//            }
+//         }
+//      }
+//      System.out.println( "   " + repeatAnnotations.size() + " Non-Consensus REPEATS!");
+//      filteredAnnotations.addAll( (Collection<T>)repeatAnnotations );
+      final List<T> nonRepeatAnnotations = new ArrayList<>();
+      for ( T filteredAnnotation : filteredAnnotations ) {
+         boolean ok = true;
+         for ( T nonRepeat : nonRepeatAnnotations ) {
+            if ( filteredAnnotation.getTextSpan().equals( nonRepeat.getTextSpan() )
+                 && filteredAnnotation.getClassType().equals( nonRepeat.getClassType() ) ) {
+               System.out.println( filteredAnnotation );
+               System.out.println( "    is the same as " );
+               System.out.println( nonRepeat );
+               ok = false;
+               break;
+            }
+         }
+         if ( ok ) {
+            nonRepeatAnnotations.add( filteredAnnotation );
+         }
+      }
+      return nonRepeatAnnotations;
+   }
+
+
+//   static public String getWantedAnnotator( final Collection<String> annotatorNames ) {
+//      if ( annotatorNames.size() == 1 ) {
+//         return ALL_ANNOTATORS;
+//      }
+//      if ( annotatorNames.contains( CONSENSUS_ANNOTATOR ) ) {
+//         return CONSENSUS_ANNOTATOR;
+//      }
+//      final List<String> sortedNames = new ArrayList<String>( annotatorNames );
+//      Collections.sort( sortedNames );
+//      sortedNames.add( ALL_ANNOTATORS );
+//      int selectedNameIndex = JOptionPane.CLOSED_OPTION;
+//      while ( selectedNameIndex == JOptionPane.CLOSED_OPTION ) {
+//         selectedNameIndex = JOptionPane.showOptionDialog( null, "Choose Desired Annotator", "Annotator Selection",
+//                                    JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
+//                                    sortedNames.toArray(), ALL_ANNOTATORS );
+//      }
+//      final String wantedAnnotator = sortedNames.get( selectedNameIndex );
+//      return wantedAnnotator;
+//   }
+
+
+   static private final String[] TYPE_NAMES = { "NamedEntity",
+                                                TemporalClassType.EVENT.getName(), TemporalClassType.TIMEX.getName(),
+                                                Relation.class.getName(),
+                                                TemporalClassType.TLINK.getName(), CoreferenceChain.class.getName() };
+
+
+   // annotatorNames : Map of type names to collection of annotator names per type
+   // conflicters : Map of annotator names to collection of types per annotator
+   static private Map<String, String> getWantedAnnotators( final Map<String, Collection<String>> annotatorNames,
+                                                           final Map<String, Collection<String>> conflicters ) {
+      if ( conflicters.size() == 0 ) {
+         System.out.println( "No Annotator for Data!!!" );
+         final Map<String, String> wantedAnnotators = new HashMap<>( 6 );
+         for ( String typeName : TYPE_NAMES ) {
+            wantedAnnotators.put( typeName, ALL_ANNOTATORS );
+         }
+         return wantedAnnotators;
+      }
+      if ( conflicters.size() == 1 ) {
+         final Map<String, String> wantedAnnotators = new HashMap<>( 6 );
+         final String wantedAnnotator = new ArrayList<>( conflicters.keySet() ).get( 0 );
+         System.out.println( "Single annotator for Data: " + wantedAnnotator );
+         for ( String typeName : TYPE_NAMES ) {
+            wantedAnnotators.put( typeName, wantedAnnotator );
+         }
+         return wantedAnnotators;
+      } else if ( conflicters.keySet().contains( CONSENSUS_ANNOTATOR ) ) {
+//            && conflicters.get( CONSENSUS_ANNOTATOR ).size() == 6 ) {
+         System.out.println( "Multiple annotators for set, but consensus annotation available for all types" );
+         final Map<String, String> wantedAnnotators = new HashMap<>( 6 );
+         for ( String typeName : TYPE_NAMES ) {
+            wantedAnnotators.put( typeName, CONSENSUS_ANNOTATOR );
+         }
+         return wantedAnnotators;
+      }
+      return getWantedConflictAnnotators( annotatorNames );
+   }
+
+   // annotatorNames : Map of type names to collection of annotator names per type
+   // conflicters : Map of annotator names to collection of types per annotator
+   static private Map<String, String> getWantedConflictAnnotators(
+         final Map<String, Collection<String>> annotatorNames ) {
+      final StringBuilder sb = new StringBuilder( "Multiple non-consensus annotators for set.\r\n" );
+      for ( Map.Entry<String, Collection<String>> typeToNames : annotatorNames.entrySet() ) {
+         sb.append( typeToNames.getKey() ).append( " :" );
+         for ( String annotatorName : typeToNames.getValue() ) {
+            sb.append( " " ).append( annotatorName );
+         }
+         sb.append( "\r\n" );
+      }
+      JOptionPane.showMessageDialog( null, sb.toString(),
+            "Annotator Conflict",
+            JOptionPane.ERROR_MESSAGE );
+      final Map<String, String> wantedAnnotators = new HashMap<>( 6 );
+      for ( Map.Entry<String, Collection<String>> typeToNames : annotatorNames.entrySet() ) {
+         final String type = typeToNames.getKey();
+         final List<String> sortedNames = new ArrayList<>( typeToNames.getValue() );
+         if ( sortedNames.isEmpty() ) {
+            continue;
+         }
+         if ( sortedNames.size() == 1 ) {
+            wantedAnnotators.put( type, sortedNames.get( 0 ) );
+            continue;
+         } else if ( sortedNames.contains( CONSENSUS_ANNOTATOR ) ) {
+            wantedAnnotators.put( type, CONSENSUS_ANNOTATOR );
+            continue;
+         }
+         Collections.sort( sortedNames );
+         sortedNames.add( ALL_ANNOTATORS );
+         int selectedNameIndex = JOptionPane.CLOSED_OPTION;
+         while ( selectedNameIndex == JOptionPane.CLOSED_OPTION ) {
+            selectedNameIndex = JOptionPane.showOptionDialog( null,
+                  sb.toString() + "Choose Desired Annotator for: " + type,
+                  "Annotator Selection", JOptionPane.OK_CANCEL_OPTION,
+                  JOptionPane.QUESTION_MESSAGE, null,
+                  sortedNames.toArray(), ALL_ANNOTATORS );
+         }
+         final String wantedAnnotator = sortedNames.get( selectedNameIndex );
+         wantedAnnotators.put( type, wantedAnnotator );
+      }
+      return wantedAnnotators;
+   }
+
+   static private String getAnnotatorName( final Map<String, Collection<String>> conflicters,
+                                           final Map<String, String> wantedAnnotators ) {
+      if ( conflicters.size() == 1 ) {
+         return new ArrayList<>( conflicters.keySet() ).get( 0 );
+      } else if ( conflicters.keySet().contains( CONSENSUS_ANNOTATOR )
+                  && conflicters.get( CONSENSUS_ANNOTATOR ).size() == 6 ) {
+         return CONSENSUS_ANNOTATOR;
+      }
+      final Collection<String> names = new HashSet<>( conflicters.keySet() );
+      if ( names.size() == 1 ) {
+         return new ArrayList<>( names ).get( 0 );
+      }
+      final StringBuilder sb = new StringBuilder();
+      for ( String name : names ) {
+         sb.append( name ).append( ", " );
+      }
+      return sb.toString();
+   }
+
+   static private final String ALL_ANNOTATORS = "All Annotators";
+   static private final String CONSENSUS_ANNOTATOR = "consensus set annotator team";
+
+   private final String _annotatorName;
+
+   private final List<Entity> _entityList;
+   private final List<Entity> _eventList;
+   private final List<Entity> _timexList;
+
+   private final List<Relation> _umlsRelationList;
+   private final List<Relation> _timeRelationList;
+   private final List<CoreferenceChain> _coreferenceChainList;
+   //   private final List<Collection<TextSpan>> _coreferenceTextSpans;      // TODO change all of these to use DefaultCoref
+   private final int _wordCount;
+   private final String _documentText;
+
+   private EntityIdCollection _entityIdCollection;
+
+   private ImmutableAnnotationStore( final AbstractBuilder builder, final boolean isMerger ) {
+//      if ( !isMerger ) {
+//         // annotatorNames : Map of type names to collection of annotator names per type
+//         final Map<String,Collection<String>> annotatorNames = getAnnotatorNames( builder.__entityList,
+//                                                                                  null,
+//                                                                                  null,
+//                                                                                  null,
+//                                                                                  null,
+//                                                                                  null );
+//         // conflicters : Map of annotator names to collection of types per annotator
+//         final Map<String,Collection<String>> conflicters = getConflictingAnnotations( annotatorNames );
+//         final Map<String,String> wantedAnnotators = getWantedAnnotators( annotatorNames, conflicters );
+//
+//         _entityList = Collections.unmodifiableList(
+//               filterAnnotators( builder.__entityList, wantedAnnotators.get( Entity.class.getName() ) ) );
+//         System.out.println( _entityList.size() + " filtered entities from " + builder.__entityList.size() + " total" );
+//         _eventList = Collections.unmodifiableList(
+//               filterAnnotators( builder.__eventList, wantedAnnotators.get( Event.class.getName() ) ) );
+//         _timexList = Collections.unmodifiableList(
+//               filterAnnotators( builder.__timexList, wantedAnnotators.get( Timex.class.getName() ) ) );
+//         _umlsRelationList = Collections.unmodifiableList(
+//               filterAnnotators( builder.__umlsRelationList, wantedAnnotators.get( Relation.class.getName() ) ) );
+//         _timeRelationList = Collections.unmodifiableList(
+//               filterAnnotators( builder.__timeRelationList, wantedAnnotators.get( "TLink" ) ) );
+//         _coreferenceChainList = Collections.unmodifiableList(
+//               filterAnnotators( builder.__coreferenceChainList, wantedAnnotators.get( CoreferenceChain.class.getName() ) ) );
+//         _annotatorName = getAnnotatorName( conflicters, wantedAnnotators );
+//      } else {
+//      final List<Entity> filteredEntities = new ArrayList<Entity>();
+//      for ( Entity entity : builder.__entityList ) {
+//         if ( entity.getClassType().equals( SemanticClassType.DISEASE_DISORDER ) ) {
+//            filteredEntities.add( entity );
+//         }
+//      }
+//      _entityList = Collections.unmodifiableList( filteredEntities );
+      _entityList = Collections.unmodifiableList( builder.__entityList );
+      _eventList = Collections.unmodifiableList( builder.__eventList );
+      _timexList = Collections.unmodifiableList( builder.__timexList );
+      _umlsRelationList = Collections.unmodifiableList( builder.__umlsRelationList );
+      _timeRelationList = Collections.unmodifiableList( builder.__timeRelationList );
+      _coreferenceChainList = Collections.unmodifiableList( builder.__coreferenceChainList );
+//         _coreferenceTextSpans = builder.__coreferenceTextSpans;
+      _annotatorName = builder.__annotatorName;
+//      }
+      _wordCount = builder.__wordCount;
+      _documentText = builder.__documentText;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public EntityIdCollection getReferenceCollection() {
+      if ( _entityIdCollection == null ) {
+         _entityIdCollection = new EntityIdCollection( this );
+      }
+      return _entityIdCollection;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public String getAnnotatorName() {
+      return _annotatorName;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Entity> getNamedEntities() {
+      return _entityList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Entity> getEvents() {
+      return _eventList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Entity> getTimes() {
+      return _timexList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Relation> getUmlsRelations() {
+      return _umlsRelationList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<Relation> getTimeRelations() {
+      return _timeRelationList;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<CoreferenceChain> getCoreferenceChains() {
+      return _coreferenceChainList;
+   }
+
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public Set<String> getEntityAnnotatorNames() {
+      return findAnnotatorNames( _entityList );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public Set<String> getEventAnnotatorNames() {
+      return findAnnotatorNames( _eventList );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public Set<String> getTimeAnnotatorNames() {
+      return findAnnotatorNames( _timexList );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public Set<String> getUmlsRelationAnnotatorNames() {
+      return findAnnotatorNames( _umlsRelationList );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public Set<String> getTimeRelationAnnotatorNames() {
+      return findAnnotatorNames( _timeRelationList );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+//   @Override
+   public Set<String> getCoreferenceAnnotatorNames() {
+      return findAnnotatorNames( _coreferenceChainList );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int getWordCount() {
+      return _wordCount;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getDocumentText() {
+      return _documentText;
+   }
+
+
+   /**
+    * @param annotationList list of annotations with named annotators
+    * @param <T>            annotation class
+    * @return a collection of all annotators that contributed annotations in the given list
+    */
+   static private <T extends Annotation> Set<String> findAnnotatorNames( final List<T> annotationList ) {
+      if ( annotationList == null || annotationList.isEmpty() ) {
+         return Collections.emptySet();
+      }
+      final Set<String> nameSet = new HashSet<>();
+      for ( T annotation : annotationList ) {
+         final String name = annotation.getAnnotatorName();
+         if ( name != null && !name.isEmpty() ) {
+            nameSet.add( name );
+         }
+      }
+      return nameSet;
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/Attribute.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/Attribute.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/Attribute.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/Attribute.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,34 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+/**
+ * There is a basic contract between Attributes in that measuring equality in names is done case insensitively
+ * <p/>
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 6/1/12
+ */
+public interface Attribute {
+
+   /**
+    * @return Human-Understandable Name of the Attribute, e.g. Severity
+    */
+   public String getName();
+
+   /**
+    * @return the defined type of this attribute
+    */
+   public AttributeType getAttributeType();
+
+   // TODO Refactor to use AttributeValue
+
+   /**
+    * @return a string representation of the value of the attribute, e.g. Mild or Severe
+    */
+   public String getValue();
+
+   /**
+    * @param value an AttributeValue that may or may not belong to this Attribute
+    * @return true if the value of this Attribute corresponds to value
+    */
+   public boolean hasAttributeValue( AttributeValue value );
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeComparatorFactory.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeComparatorFactory.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeComparatorFactory.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeComparatorFactory.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,173 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+import sun.misc.ASCIICaseInsensitiveComparator;
+
+import java.util.Comparator;
+
+/**
+ * Not yet used...
+ * <p/>
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 6/6/12
+ */
+final public class AttributeComparatorFactory {
+
+   private AttributeComparatorFactory() {
+   }
+
+
+   static public Comparator<Attribute> getAttributeComparator( final String attributeName ) {
+      if ( attributeName.equalsIgnoreCase( "SEVERITY" ) ) {
+         return SeverityComparator.INSTANCE;
+      } else if ( attributeName.equalsIgnoreCase( "LONGEVITY" ) ) {
+         return LongevityComparator.INSTANCE;
+      } else if ( attributeName.equalsIgnoreCase( "SUBJECT" ) ) {
+         return SubjectComparator.INSTANCE;
+      } else if ( attributeName.equalsIgnoreCase( "DOCUMENT RELATIVE TIME" ) ) {
+         return DocRelTimeComparator.INSTANCE;
+      }
+      return DefaultAttributeComparator.INSTANCE;
+   }
+
+   static private enum DefaultAttributeComparator implements Comparator<Attribute> {
+      INSTANCE;
+
+      public int compare( final Attribute attribute1, final Attribute attribute2 ) {
+         return ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER.compare( attribute1.getValue(),
+               attribute2.getValue() );
+      }
+   }
+
+   abstract static private class LogComparator implements Comparator<Attribute> {
+      private final String __attributeName;
+
+      protected LogComparator( final String attributeName ) {
+         __attributeName = attributeName;
+      }
+
+      abstract double getOrder( final String attributeValue );
+
+      public int compare( final Attribute attribute1, final Attribute attribute2 ) {
+         if ( !__attributeName.equalsIgnoreCase( attribute1.getName() )
+              || !__attributeName.equalsIgnoreCase( attribute2.getName() ) ) {
+            throw new IllegalArgumentException(
+                  "Attempting to contrast attributes that are not both type " + __attributeName );
+         }
+         // division gets us a power of 10 < 1 if attribute1 < attribute2, or
+         // > 1 if attribute2 > attribute1, or
+         // == 1 if attribute1 == attribute2
+         final double div = getOrder( attribute1.getValue() ) / getOrder( attribute2.getValue() );
+         // if div < 1 then log < 0, if div > 1 then log > 0, if div == 1 then log == 0
+         return (int)Math.log10( div );
+      }
+   }
+
+   static private class SimpleLogComparator extends LogComparator {
+      private final String[] __orderedValues;
+
+      protected SimpleLogComparator( final String attributeName, final String... orderedValues ) {
+         super( attributeName );
+         __orderedValues = orderedValues;
+      }
+
+      double getOrder( final String attributeValue ) {
+         final String lower = attributeValue.toLowerCase();
+         double power10 = 1;
+         for ( String value : __orderedValues ) {
+            if ( value.equals( lower ) ) {
+               return power10;
+            }
+            power10 *= 10;
+         }
+         // default to (roughly) the median
+         return Math.pow( 10d, (__orderedValues.length / 2) );
+      }
+   }
+
+   static private class SeverityComparator extends SimpleLogComparator {
+      static SeverityComparator INSTANCE = new SeverityComparator();
+
+      private SeverityComparator() {
+         super( "SEVERITY", "mild", "moderate", "severe" );
+      }
+   }
+
+   // This cannot be a SimpleLogComparator because it has two equal values of "subacute" and "sub-acute"
+   static private class LongevityComparator extends LogComparator {
+      static LongevityComparator INSTANCE = new LongevityComparator();
+
+      private LongevityComparator() {
+         super( "LONGEVITY" );
+      }
+
+      // return some power of 10 >= 1
+      double getOrder( final String attributeValue ) {
+         final String lower = attributeValue.toLowerCase();
+         if ( lower.equals( "acute" ) ) {
+            return 1d;
+         } else if ( lower.equals( "subacute" ) || lower.equals( "sub-acute" ) ) {
+            return 10d;
+         } else if ( lower.equals( "intermittent" ) || lower.equals( "recurrent" ) ) {
+            return 100d;
+         } else if ( lower.equals( "persistent" ) ) {
+            return 1000d;
+         } else if ( lower.equals( "chronic" ) ) {
+            return 10000d;
+         }
+         // default for an unknown or unspecified longevity is "persistent"
+         return 100d;
+      }
+   }
+
+   static private class SubjectComparator extends SimpleLogComparator {
+      static SubjectComparator INSTANCE = new SubjectComparator();
+
+      private SubjectComparator() {
+         super( "SUBJECT", "patient", "family member", "other" );
+      }
+   }
+
+   static private class DocRelTimeComparator extends SimpleLogComparator {
+      static DocRelTimeComparator INSTANCE = new DocRelTimeComparator();
+
+      private DocRelTimeComparator() {
+         super( "DOCUMENT RELATIVE TIME", "before", "before/overlap", "overlap", "after" );
+      }
+   }
+
+   static private class TLinkRelTypeComparator extends SimpleLogComparator {
+      static TLinkRelTypeComparator INSTANCE = new TLinkRelTypeComparator();
+
+      private TLinkRelTypeComparator() {
+         super( "RELATION TYPE", "before", "overlap", "after" );
+      }
+   }
+
+   static private class ALinkRelTypeComparator extends LogComparator {
+      static ALinkRelTypeComparator INSTANCE = new ALinkRelTypeComparator();
+
+      private ALinkRelTypeComparator() {
+         super( "RELATION TYPE" );
+      }
+
+      // return some power of 10 >= 1
+      double getOrder( final String attributeValue ) {
+         final String lower = attributeValue.toLowerCase();
+         if ( lower.equals( "begins-on" ) || lower.equals( "initiates" ) ) {
+            return 1d;
+         } else if ( lower.equals( "contains" ) ) {
+            return 10d;
+         } else if ( lower.equals( "continues" ) ) {
+            return 100d;
+         } else if ( lower.equals( "reinitiates" ) ) {
+            return 1000d;
+         } else if ( lower.equals( "terminates" ) ) {
+            return 10000d;
+         }
+         // default for an unknown or unspecified relation is "continues"
+         return 100d;
+      }
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeType.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeType.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeType.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeType.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,19 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+/**
+ * Annotations can have one or more attributes, each being of an attribute type
+ * <p/>
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/21/12
+ */
+public interface AttributeType {
+
+   /**
+    * @return Human - Readable Name of the AttributeType
+    */
+   public String getName();
+
+   // TODO Add getPossibleValues() ??
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeTypeFactory.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeTypeFactory.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeTypeFactory.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeTypeFactory.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,30 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+
+/**
+ * Utility class that creates Attribute Types from their names
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/21/12
+ */
+final public class AttributeTypeFactory {
+
+   private AttributeTypeFactory() {
+   }
+
+   /**
+    * @param name of the attribute
+    * @return an AttributeType
+    */
+   static public AttributeType getAttributeForName( final String name ) {
+      if ( name == null || name.isEmpty() ) {
+         return UnknownAttributeType.getInstance();
+      }
+      final DefinedAttributeType definedAttributeType = DefinedAttributeType.getDefinedAttibuteType( name );
+      if ( definedAttributeType != null ) {
+         return definedAttributeType;
+      }
+      return new CustomAttributeType( name );
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeUtil.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeUtil.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeUtil.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeUtil.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,92 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+import org.chboston.cnlp.nlp.annotation.annotation.Annotation;
+import org.chboston.cnlp.nlp.annotation.coreference.CoreferenceChain;
+import org.chboston.cnlp.nlp.annotation.relation.Relation;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/8/13
+ */
+final public class AttributeUtil {
+
+   private AttributeUtil() {
+   }
+
+
+   // TODO refactor to return EventStatus
+   static public boolean hasNegativePolarity( final Annotation annotation ) {
+      if ( annotation instanceof CoreferenceChain ) {
+         for ( Annotation link : (CoreferenceChain)annotation ) {
+            if ( hasNegativePolarity( link ) ) {
+               return true;
+            }
+         }
+      }
+      final Attribute polarity = annotation.getAttribute( DefinedAttributeType.POLARITY );
+      if ( polarity == null ) {
+         return false;
+      }
+      final EventAttributeValue polarityValue = getEventAttributeValue( polarity, EventAttributeValue.POSITIVE );
+      return polarityValue != null
+             && (polarityValue == EventAttributeValue.NEGATIVE || polarityValue == EventAttributeValue.NEGATED);
+   }
+
+   static public boolean hasUncertainty( final Annotation annotation ) {
+      if ( annotation instanceof CoreferenceChain ) {
+         for ( Annotation link : (CoreferenceChain)annotation ) {
+            if ( hasUncertainty( link ) ) {
+               return true;
+            }
+         }
+      }
+      final Attribute modality = annotation.getAttribute( DefinedAttributeType.CONTEXT_MODALITY );
+      if ( modality == null ) {
+         return false;
+      }
+      final EventAttributeValue modalityValue = getEventAttributeValue( modality, null );
+      if ( modalityValue != null
+           && (modalityValue == EventAttributeValue.HYPOTHETICAL || modalityValue == EventAttributeValue.HEDGED) ) {
+         return true;
+      }
+      return false;
+   }
+
+   static public TlinkAttributeValue getTlinkType( final Relation tlink ) {
+      Attribute relationType = tlink.getAttribute( DefinedAttributeType.RELATION_TYPE );
+      if ( relationType == null ) {
+         relationType = tlink.getAttribute( DefinedAttributeType.TYPE );
+      }
+      // There is currently no default relation type in the thyme schema, but we must have one, so use overlap
+      return getTlinkAttributeValue( relationType, TlinkAttributeValue.OVERLAP );
+   }
+
+
+   static public EventAttributeValue getEventAttributeValue( final Attribute attribute,
+                                                             final EventAttributeValue defaultValue ) {
+      if ( attribute == null ) {
+         return defaultValue;
+      }
+      for ( EventAttributeValue value : EventAttributeValue.values() ) {
+         if ( attribute.hasAttributeValue( value ) ) {
+            return value;
+         }
+      }
+      return defaultValue;
+   }
+
+   static public TlinkAttributeValue getTlinkAttributeValue( final Attribute attribute,
+                                                             final TlinkAttributeValue defaultValue ) {
+      if ( attribute == null ) {
+         return defaultValue;
+      }
+      for ( TlinkAttributeValue value : TlinkAttributeValue.values() ) {
+         if ( attribute.hasAttributeValue( value ) ) {
+            return value;
+         }
+      }
+      return defaultValue;
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeValue.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeValue.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeValue.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/AttributeValue.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,21 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 8/8/13
+ */
+public interface AttributeValue {
+
+   /**
+    * @return a human - readable name for the attribute
+    */
+   String getName();
+
+   /**
+    * @param key some key, possibly from a parsed annotation schema or xmi, etc.
+    * @return true if the key applies to this Attribute value
+    */
+   boolean isAttributeValue( String key );
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CreatorAttributeValue.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CreatorAttributeValue.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CreatorAttributeValue.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CreatorAttributeValue.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,42 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 6/9/14
+ */
+public enum CreatorAttributeValue implements AttributeValue {
+   ANNOTATOR( "Annotator", "ANNOTATOR" ),
+   SYSTEM( "System", "SYSTEM" ),
+   CLOSURE( "Closure", "CLOSURE" );
+
+   private final String _name;
+   private final Collection<String> _keys;
+
+   private CreatorAttributeValue( final String name, final String... keys ) {
+      _name = name;
+      _keys = new HashSet<>( keys.length );
+      _keys.addAll( Arrays.asList( keys ) );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getName() {
+      return _name;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean isAttributeValue( final String key ) {
+      return key != null && _keys.contains( key.toUpperCase() );
+   }
+
+}

Added: ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CustomAttributeType.java
URL: http://svn.apache.org/viewvc/ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CustomAttributeType.java?rev=1660963&view=auto
==============================================================================
--- ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CustomAttributeType.java (added)
+++ ctakes/sandbox/timelanes/org/chboston/cnlp/nlp/annotation/attribute/CustomAttributeType.java Thu Feb 19 18:06:13 2015
@@ -0,0 +1,44 @@
+package org.chboston.cnlp.nlp.annotation.attribute;
+
+/**
+ * For any AttributeType that is not predefined
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 5/21/12
+ */
+final public class CustomAttributeType implements AttributeType {
+
+   private final String _name;
+
+   /**
+    * @param name the name or description of the custom attribute type
+    */
+   public CustomAttributeType( final String name ) {
+      _name = name;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String getName() {
+      return _name;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals( final Object value ) {
+      return value instanceof AttributeType && ((AttributeType)value).getName().equals( _name );
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return _name.hashCode();
+   }
+
+}



Mime
View raw message