You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ctakes.apache.org by cl...@apache.org on 2014/04/17 22:12:28 UTC
svn commit: r1588359 - in
/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal: ae/
eval/ utils/
Author: clin
Date: Thu Apr 17 20:12:28 2014
New Revision: 1588359
URL: http://svn.apache.org/r1588359
Log:
add transitive closure for event-time relation discovery. Closure was added for both training and testing, and both gold relations and system predictions.
Added:
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/AnnotationIdCollection.java (with props)
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TLinkTypeArray2.java (with props)
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TimeRelationConstants.java (with props)
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkType.java (with props)
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkTypeSet.java (with props)
Modified:
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/ae/EventTimeRelationAnnotator.java
ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/eval/EvaluationOfEventTimeRelations.java
Modified: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/ae/EventTimeRelationAnnotator.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/ae/EventTimeRelationAnnotator.java?rev=1588359&r1=1588358&r2=1588359&view=diff
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/ae/EventTimeRelationAnnotator.java (original)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/ae/EventTimeRelationAnnotator.java Thu Apr 17 20:12:28 2014
@@ -9,12 +9,16 @@ import org.apache.ctakes.relationextract
import org.apache.ctakes.relationextractor.ae.features.PartOfSpeechFeaturesExtractor;
import org.apache.ctakes.relationextractor.ae.features.RelationFeaturesExtractor;
import org.apache.ctakes.relationextractor.ae.features.TokenFeaturesExtractor;
-import org.apache.ctakes.temporal.ae.feature.DependencyFeatureExtractor;
+import org.apache.ctakes.temporal.ae.feature.CheckSpecialWordRelationExtractor;
+import org.apache.ctakes.temporal.ae.feature.DependencyPathFeaturesExtractor;
+import org.apache.ctakes.temporal.ae.feature.NearbyVerbTenseRelationExtractor;
import org.apache.ctakes.temporal.ae.feature.NearestFlagFeatureExtractor;
+import org.apache.ctakes.temporal.ae.feature.SectionHeaderRelationExtractor;
//import org.apache.ctakes.temporal.ae.feature.TemporalAttributeFeatureExtractor;
-import org.apache.ctakes.temporal.ae.feature.treekernel.EventTimeFlatTreeFeatureExtractor;
+//import org.apache.ctakes.temporal.ae.feature.treekernel.EventTimeFlatTreeFeatureExtractor;
+//import org.apache.ctakes.temporal.ae.feature.treekernel.EventVerbRelationTreeExtractor;
import org.apache.ctakes.temporal.ae.feature.treekernel.TemporalPETExtractor;
-import org.apache.ctakes.temporal.ae.feature.treekernel.TemporalPathExtractor;
+//import org.apache.ctakes.temporal.ae.feature.treekernel.TemporalPathExtractor;
import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
import org.apache.ctakes.typesystem.type.textsem.EventMention;
import org.apache.ctakes.typesystem.type.textsem.IdentifiedAnnotation;
@@ -69,11 +73,16 @@ public class EventTimeRelationAnnotator
new TokenFeaturesExtractor()
, new PartOfSpeechFeaturesExtractor()
// , new TemporalAttributeFeatureExtractor()
- , new EventTimeFlatTreeFeatureExtractor()
+// , new EventTimeFlatTreeFeatureExtractor()
, new TemporalPETExtractor()
- , new TemporalPathExtractor()
+// , new TemporalPathExtractor()
+// , new EventVerbRelationTreeExtractor()
+ , new SectionHeaderRelationExtractor()
+ , new NearbyVerbTenseRelationExtractor()
+ , new CheckSpecialWordRelationExtractor()
, new NearestFlagFeatureExtractor()
- , new DependencyFeatureExtractor()
+ , new DependencyPathFeaturesExtractor()
+// , new DependencyFeatureExtractor()
);
}
@@ -95,9 +104,32 @@ public class EventTimeRelationAnnotator
}
}
}
+
+ //only use gold pairs:
+// for (BinaryTextRelation relation : JCasUtil.select(jCas, BinaryTextRelation.class)) {
+// Annotation arg1 = relation.getArg1().getArgument();
+// Annotation arg2 = relation.getArg2().getArgument();
+// EventMention event = null;
+// TimeMention time = null;
+// if(arg1 instanceof EventMention){
+// event = (EventMention) arg1;
+// }else if(arg1 instanceof TimeMention){
+// time = (TimeMention) arg1;
+// }
+// if(arg2 instanceof EventMention){
+// event = (EventMention) arg2;
+// }else if(arg2 instanceof TimeMention){
+// time = (TimeMention) arg2;
+// }
+// if(event != null && time != null){
+// pairs.add(new IdentifiedAnnotationPair(event, time));
+// }
+// }
+
return pairs;
}
+
@Override
protected String getRelationCategory(
Map<List<Annotation>, BinaryTextRelation> relationLookup,
@@ -110,7 +142,11 @@ public class EventTimeRelationAnnotator
} else {
relation = relationLookup.get(Arrays.asList(arg2, arg1));
if (relation != null) {
- category = relation.getCategory() + "-1";
+ if(relation.getCategory().equals("OVERLAP")){
+ category = relation.getCategory();
+ }else{
+ category = relation.getCategory() + "-1";
+ }
}
}
if (category == null && coin.nextDouble() <= this.probabilityOfKeepingANegativeExample) {
Modified: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/eval/EvaluationOfEventTimeRelations.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/eval/EvaluationOfEventTimeRelations.java?rev=1588359&r1=1588358&r2=1588359&view=diff
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/eval/EvaluationOfEventTimeRelations.java (original)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/eval/EvaluationOfEventTimeRelations.java Thu Apr 17 20:12:28 2014
@@ -34,6 +34,8 @@ import org.apache.ctakes.relationextract
import org.apache.ctakes.temporal.ae.EventTimeRelationAnnotator;
import org.apache.ctakes.temporal.ae.baselines.RecallBaselineEventTimeRelationAnnotator;
import org.apache.ctakes.temporal.eval.EvaluationOfTemporalRelations_ImplBase.RemoveNonContainsRelations.RemoveGoldAttributes;
+import org.apache.ctakes.temporal.utils.AnnotationIdCollection;
+import org.apache.ctakes.temporal.utils.TLinkTypeArray2;
import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
import org.apache.ctakes.typesystem.type.relation.RelationArgument;
import org.apache.ctakes.typesystem.type.textsem.EventMention;
@@ -221,15 +223,18 @@ EvaluationOfTemporalRelations_ImplBase{
// if(this.baseline) return;
AggregateBuilder aggregateBuilder = this.getPreprocessorAggregateBuilder();
aggregateBuilder.add(CopyFromGold.getDescription(EventMention.class, TimeMention.class, BinaryTextRelation.class));
- aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(RemoveNonContainsRelations.class));
aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(RemoveCrossSentenceRelations.class));
if(!this.useGoldAttributes){
aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(RemoveGoldAttributes.class));
}
if (this.useClosure) {
- aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveContainsRelations.class));
+ aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(AddClosure.class));//aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveContainsRelations.class));
+// aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(AddContain2Overlap.class));
// aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveBeforeAndOnRelations.class));
}
+// aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(RemoveNonContainsRelations.class));
+ aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(AddFlippedOverlap.class));//add flipped overlap instances to training data
+
aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(RemoveEventEventRelations.class));
aggregateBuilder.add(EventTimeRelationAnnotator.createDataWriterDescription(
// LIBSVMStringOutcomeDataWriter.class,
@@ -274,10 +279,7 @@ EvaluationOfTemporalRelations_ImplBase{
throws Exception {
AggregateBuilder aggregateBuilder = this.getPreprocessorAggregateBuilder();
aggregateBuilder.add(CopyFromGold.getDescription(EventMention.class, TimeMention.class));
- aggregateBuilder.add(
- AnalysisEngineFactory.createPrimitiveDescription(RemoveNonContainsRelations.class,
- RemoveNonContainsRelations.PARAM_RELATION_VIEW,
- GOLD_VIEW_NAME));
+
aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(
RemoveCrossSentenceRelations.class,
RemoveCrossSentenceRelations.PARAM_SENTENCE_VIEW,
@@ -286,14 +288,24 @@ EvaluationOfTemporalRelations_ImplBase{
GOLD_VIEW_NAME));
if (this.useClosure) {
aggregateBuilder.add(
- AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveContainsRelations.class),
+ AnalysisEngineFactory.createPrimitiveDescription(AddClosure.class),//AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveContainsRelations.class),
CAS.NAME_DEFAULT_SOFA,
GOLD_VIEW_NAME);
+
+// aggregateBuilder.add(
+// AnalysisEngineFactory.createPrimitiveDescription(AddContain2Overlap.class),
+// CAS.NAME_DEFAULT_SOFA,
+// GOLD_VIEW_NAME);
// aggregateBuilder.add(
// AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveBeforeAndOnRelations.class),
// CAS.NAME_DEFAULT_SOFA,
// GOLD_VIEW_NAME);
}
+
+// aggregateBuilder.add(
+// AnalysisEngineFactory.createPrimitiveDescription(RemoveNonContainsRelations.class,
+// RemoveNonContainsRelations.PARAM_RELATION_VIEW,
+// GOLD_VIEW_NAME));
aggregateBuilder.add(
AnalysisEngineFactory.createPrimitiveDescription(RemoveEventEventRelations.class),
CAS.NAME_DEFAULT_SOFA,
@@ -302,7 +314,15 @@ EvaluationOfTemporalRelations_ImplBase{
aggregateBuilder.add(AnalysisEngineFactory.createPrimitiveDescription(RemoveRelations.class));
aggregateBuilder.add(this.baseline ? RecallBaselineEventTimeRelationAnnotator.createAnnotatorDescription(directory) :
EventTimeRelationAnnotator.createAnnotatorDescription(directory));
-
+
+ if (this.useClosure) {//add closure for system output
+ aggregateBuilder.add(
+ AnalysisEngineFactory.createPrimitiveDescription(AddClosure.class),//AnalysisEngineFactory.createPrimitiveDescription(AddTransitiveContainsRelations.class),
+ GOLD_VIEW_NAME,
+ CAS.NAME_DEFAULT_SOFA
+ );
+ }
+
Function<BinaryTextRelation, ?> getSpan = new Function<BinaryTextRelation, HashableArguments>() {
public HashableArguments apply(BinaryTextRelation relation) {
return new HashableArguments(relation);
@@ -416,25 +436,25 @@ EvaluationOfTemporalRelations_ImplBase{
}
*/
- // private static <SPAN_TYPE> Collection<BinaryTextRelation> removeNonGoldRelations(
- // Collection<BinaryTextRelation> systemRelations,
- // Collection<BinaryTextRelation> goldRelations, Function<BinaryTextRelation, ?> getSpan) {
- // //remove non-gold pairs from system relations:
- // Set<BinaryTextRelation> goodSys = Sets.newHashSet();
- // Set<SPAN_TYPE> goldspans = new HashSet<SPAN_TYPE>();
- //
- // for (BinaryTextRelation relation : goldRelations) {
- // goldspans.add(((SPAN_TYPE) getSpan.apply(relation)));
- // }
- //
- // for (BinaryTextRelation relation : systemRelations) {
- // if (goldspans.contains(((SPAN_TYPE) getSpan.apply(relation)))) {
- // goodSys.add(relation);
- // }
- // }
- //
- // return goodSys;
- // }
+// private static <SPAN_TYPE> Collection<BinaryTextRelation> removeNonGoldRelations(
+// Collection<BinaryTextRelation> systemRelations,
+// Collection<BinaryTextRelation> goldRelations, Function<BinaryTextRelation, ?> getSpan) {
+// //remove non-gold pairs from system relations:
+// Set<BinaryTextRelation> goodSys = Sets.newHashSet();
+// Set<SPAN_TYPE> goldspans = new HashSet<SPAN_TYPE>();
+//
+// for (BinaryTextRelation relation : goldRelations) {
+// goldspans.add(((SPAN_TYPE) getSpan.apply(relation)));
+// }
+//
+// for (BinaryTextRelation relation : systemRelations) {
+// if (goldspans.contains(((SPAN_TYPE) getSpan.apply(relation)))) {
+// goodSys.add(relation);
+// }
+// }
+//
+// return goodSys;
+// }
private static Collection<BinaryTextRelation> correctArgOrder(
Collection<BinaryTextRelation> systemRelations,
@@ -776,108 +796,270 @@ EvaluationOfTemporalRelations_ImplBase{
}
}
-
- public static class AddTransitiveBeforeAndOnRelations extends JCasAnnotator_ImplBase {
+
+ public static class AddContain2Overlap extends JCasAnnotator_ImplBase {
@Override
public void process(JCas jCas) throws AnalysisEngineProcessException {
- // collect many-to-many mappings of containment relations
- Multimap<Annotation, Annotation> contains = HashMultimap.create();
- Multimap<Annotation, Annotation> before = HashMultimap.create();
- Multimap<Annotation, Annotation> endson = HashMultimap.create();
- Multimap<Annotation, Annotation> beginson = HashMultimap.create();
- Set<BinaryTextRelation> beforeRel = Sets.newHashSet();
-
+ Set<BinaryTextRelation> containsRelations = Sets.newHashSet();
for (BinaryTextRelation relation : JCasUtil.select(jCas, BinaryTextRelation.class)) {
if (relation.getCategory().equals("CONTAINS")) {
+ containsRelations.add(relation);
+ }
+ }
+
+ for (BinaryTextRelation relation : containsRelations) {
+ RelationArgument arg1 = (RelationArgument) relation.getArg1().clone();
+ RelationArgument arg2 = (RelationArgument) relation.getArg2().clone();
+ BinaryTextRelation newrelation = new BinaryTextRelation(jCas);
+ newrelation.setArg1(arg1);
+ newrelation.setArg2(arg2);
+ newrelation.setCategory("OVERLAP");
+ arg1.addToIndexes();
+ arg2.addToIndexes();
+ newrelation.addToIndexes();
+ }
+ }
+ }
+
+ public static class AddFlippedOverlap extends JCasAnnotator_ImplBase {
+
+ @Override
+ public void process(JCas jCas) throws AnalysisEngineProcessException {
+
+ Set<BinaryTextRelation> overlapRelations = Sets.newHashSet();
+ Multimap<Annotation, Annotation> overlaps = HashMultimap.create();
+ for (BinaryTextRelation relation : JCasUtil.select(jCas, BinaryTextRelation.class)) {
+ if (relation.getCategory().equals("OVERLAP")) {
+ overlapRelations.add(relation);
Annotation arg1 = relation.getArg1().getArgument();
Annotation arg2 = relation.getArg2().getArgument();
- contains.put(arg1, arg2);
- }else if (relation.getCategory().equals("BEFORE")) {
- Annotation arg1 = relation.getArg1().getArgument();
- Annotation arg2 = relation.getArg2().getArgument();
- before.put(arg1, arg2);
- beforeRel.add(relation);
- }else if (relation.getCategory().equals("ENDS-ON")) {
- Annotation arg1 = relation.getArg1().getArgument();
- Annotation arg2 = relation.getArg2().getArgument();
- endson.put(arg1, arg2);
- if (!endson.containsEntry(arg2, arg1)) {
- endson.put(arg2, arg1);
- }
- }else if (relation.getCategory().equals("BEGINS-ON")) {
- Annotation arg1 = relation.getArg1().getArgument();
- Annotation arg2 = relation.getArg2().getArgument();
- beginson.put(arg1, arg2);
- if (!beginson.containsEntry(arg2, arg1)) {
- beginson.put(arg2, arg1);
- }
+ overlaps.put(arg1, arg2);
}
}
- // for A BEFORE B, check if A and B Contain anything
- for (BinaryTextRelation brelation : beforeRel) {
- Annotation argA = brelation.getArg1().getArgument();
- Annotation argB = brelation.getArg2().getArgument();
- //add contained before
- for (Annotation childA : contains.get(argA)) {
- for (Annotation childB : contains.get(argB)) {
- if (!before.containsEntry(childA, childB)) {
- //create a new before relation:
- RelationArgument arg1 = new RelationArgument(jCas);
- arg1.setArgument(childA);
- RelationArgument arg2 = new RelationArgument(jCas);
- arg2.setArgument(childB);
- BinaryTextRelation relation = new BinaryTextRelation(jCas);
- relation.setArg1(arg1);
- relation.setArg2(arg2);
- relation.setCategory("BEFORE");
- arg1.addToIndexes();
- arg2.addToIndexes();
- relation.addToIndexes();
- before.put(childA, childB);
+ for (BinaryTextRelation orelation : overlapRelations) {
+ Annotation argA = orelation.getArg1().getArgument();
+ Annotation argB = orelation.getArg2().getArgument();
+ //add overlap
+ if (!overlaps.containsEntry(argB, argA)) {
+ //create a new flipped relation:
+ RelationArgument arg1 = new RelationArgument(jCas);
+ arg1.setArgument(argB);
+ RelationArgument arg2 = new RelationArgument(jCas);
+ arg2.setArgument(argA);
+ BinaryTextRelation relation = new BinaryTextRelation(jCas);
+ relation.setArg1(arg1);
+ relation.setArg2(arg2);
+ relation.setCategory("OVERLAP");
+ arg1.addToIndexes();
+ arg2.addToIndexes();
+ relation.addToIndexes();
+ overlaps.put(argB, argA);
+ }
+
+ }
+ }
+ }
+
+ public static class AddClosure extends JCasAnnotator_ImplBase {
+
+ @Override
+ public void process(JCas jCas) throws AnalysisEngineProcessException {
+
+ Multimap<List<Annotation>, BinaryTextRelation> annotationsToRelation = HashMultimap.create();
+ for (BinaryTextRelation relation : JCasUtil.select(jCas, BinaryTextRelation.class)){
+ String relationType = relation.getCategory();
+ if(validTemporalType(relationType)){
+ Annotation arg1 = relation.getArg1().getArgument();
+ Annotation arg2 = relation.getArg2().getArgument();
+ annotationsToRelation.put(Arrays.asList(arg1, arg2), relation);
+ }
+ }
+ for (List<Annotation> span: Lists.newArrayList(annotationsToRelation.keySet())){
+ Collection<BinaryTextRelation> relations = annotationsToRelation.get(span);
+ if(relations.size()>1){//if same span maps to multiple relations
+ Set<String> types = Sets.newHashSet();
+ for(BinaryTextRelation relation: relations){
+ types.add(relation.getCategory());
+ }
+ if(types.size()>1){
+ for(BinaryTextRelation relation: Lists.newArrayList(relations)){
+ annotationsToRelation.remove(span, relation);
+ relation.getArg1().removeFromIndexes();
+ relation.getArg2().removeFromIndexes();
+ relation.removeFromIndexes();
+ }
+ }else if(types.size()==1){
+ for (int i =1; i< relations.size(); i++){
+ BinaryTextRelation relation = (BinaryTextRelation) relations.toArray()[i];
+ annotationsToRelation.remove(span, relation);
+ relation.getArg1().removeFromIndexes();
+ relation.getArg2().removeFromIndexes();
+ relation.removeFromIndexes();
}
}
}
- //add ends-on A
- for (Annotation endsOnA : endson.get(argA)) {
- if (!before.containsEntry(endsOnA, argB)) {
- //create a new before relation:
- RelationArgument arg1 = new RelationArgument(jCas);
- arg1.setArgument(endsOnA);
- RelationArgument arg2 = new RelationArgument(jCas);
- arg2.setArgument(argB);
- BinaryTextRelation relation = new BinaryTextRelation(jCas);
- relation.setArg1(arg1);
- relation.setArg2(arg2);
- relation.setCategory("BEFORE");
- arg1.addToIndexes();
- arg2.addToIndexes();
- relation.addToIndexes();
- before.put(endsOnA, argB);
+ }
+
+ ArrayList<BinaryTextRelation> temporalRelation = new ArrayList<BinaryTextRelation>(annotationsToRelation.values());//new ArrayList<BinaryTextRelation>();
+// Map<List<Annotation>, BinaryTextRelation> temporalRelationLookup = new HashMap<List<Annotation>, BinaryTextRelation>();
+//
+// for (BinaryTextRelation relation : JCasUtil.select(jCas, BinaryTextRelation.class)){
+// String relationType = relation.getCategory();
+// if(validTemporalType(relationType)){
+// Annotation arg1 = relation.getArg1().getArgument();
+// Annotation arg2 = relation.getArg2().getArgument();
+// BinaryTextRelation tempRelation = temporalRelationLookup.get(Arrays.asList(arg1, arg2));
+// if( tempRelation == null){
+// temporalRelation.add(relation);
+// temporalRelationLookup.put(Arrays.asList(arg1, arg2), relation);
+// }else{//if there is duplicate
+// relation.getArg1().removeFromIndexes();
+// relation.getArg2().removeFromIndexes();
+// relation.removeFromIndexes();
+// }
+//
+// }
+// }
+
+ if (!temporalRelation.isEmpty()){
+ TLinkTypeArray2 relationArray = new TLinkTypeArray2(temporalRelation, new AnnotationIdCollection(temporalRelation));
+
+ int addedCount = 0;
+ for (BinaryTextRelation relation : relationArray.getClosedTlinks(jCas)) {
+ RelationArgument arg1 = relation.getArg1();
+ RelationArgument arg2 = relation.getArg2();
+ String relationType = relation.getCategory();
+ if(relationType.equals("CONTAINED-BY")||relationType.equals("AFTER")){//ignore these two categories, because their reciprocal already exist.
+ continue;
}
- }
- //add begins-on B
- for (Annotation beginsOnB : beginson.get(argB)) {
- if (!before.containsEntry(argA, beginsOnB)) {
- //create a new before relation:
- RelationArgument arg1 = new RelationArgument(jCas);
- arg1.setArgument(argA);
- RelationArgument arg2 = new RelationArgument(jCas);
- arg2.setArgument(beginsOnB);
- BinaryTextRelation relation = new BinaryTextRelation(jCas);
- relation.setArg1(arg1);
- relation.setArg2(arg2);
- relation.setCategory("BEFORE");
+ //check if the inferred relation new:
+ Collection<BinaryTextRelation> relations = annotationsToRelation.get(Arrays.asList(arg1.getArgument(), arg2.getArgument()));
+ if(relations.isEmpty()){ //if haven't seen this inferred relation before, then add this relation
arg1.addToIndexes();
arg2.addToIndexes();
relation.addToIndexes();
- before.put(argA, beginsOnB);
- }
+ addedCount++;
+ }
}
- }
+
+ System.out.println( "**************************************************************");
+ System.out.println( "Finally added closure relations: " + addedCount );
+ System.out.println( "**************************************************************");
+ }
+
}
+ private static boolean validTemporalType(String relationType) {
+ if(relationType.equals("CONTAINS")||relationType.equals("OVERLAP")||relationType.equals("BEFORE")||relationType.equals("ENDS-ON")||relationType.equals("BEGINS-ON"))
+ return true;
+ return false;
+ }
}
+
+// public static class AddTransitiveBeforeAndOnRelations extends JCasAnnotator_ImplBase {
+//
+// @Override
+// public void process(JCas jCas) throws AnalysisEngineProcessException {
+//
+// // collect many-to-many mappings of containment relations
+// Multimap<Annotation, Annotation> contains = HashMultimap.create();
+// Multimap<Annotation, Annotation> before = HashMultimap.create();
+// Multimap<Annotation, Annotation> endson = HashMultimap.create();
+// Multimap<Annotation, Annotation> beginson = HashMultimap.create();
+// Set<BinaryTextRelation> beforeRel = Sets.newHashSet();
+//
+// for (BinaryTextRelation relation : JCasUtil.select(jCas, BinaryTextRelation.class)) {
+// if (relation.getCategory().equals("CONTAINS")) {
+// Annotation arg1 = relation.getArg1().getArgument();
+// Annotation arg2 = relation.getArg2().getArgument();
+// contains.put(arg1, arg2);
+// }else if (relation.getCategory().equals("BEFORE")) {
+// Annotation arg1 = relation.getArg1().getArgument();
+// Annotation arg2 = relation.getArg2().getArgument();
+// before.put(arg1, arg2);
+// beforeRel.add(relation);
+// }else if (relation.getCategory().equals("ENDS-ON")) {
+// Annotation arg1 = relation.getArg1().getArgument();
+// Annotation arg2 = relation.getArg2().getArgument();
+// endson.put(arg1, arg2);
+// if (!endson.containsEntry(arg2, arg1)) {
+// endson.put(arg2, arg1);
+// }
+// }else if (relation.getCategory().equals("BEGINS-ON")) {
+// Annotation arg1 = relation.getArg1().getArgument();
+// Annotation arg2 = relation.getArg2().getArgument();
+// beginson.put(arg1, arg2);
+// if (!beginson.containsEntry(arg2, arg1)) {
+// beginson.put(arg2, arg1);
+// }
+// }
+// }
+//
+// // for A BEFORE B, check if A and B Contain anything
+// for (BinaryTextRelation brelation : beforeRel) {
+// Annotation argA = brelation.getArg1().getArgument();
+// Annotation argB = brelation.getArg2().getArgument();
+// //add contained before
+// for (Annotation childA : contains.get(argA)) {
+// for (Annotation childB : contains.get(argB)) {
+// if (!before.containsEntry(childA, childB)) {
+// //create a new before relation:
+// RelationArgument arg1 = new RelationArgument(jCas);
+// arg1.setArgument(childA);
+// RelationArgument arg2 = new RelationArgument(jCas);
+// arg2.setArgument(childB);
+// BinaryTextRelation relation = new BinaryTextRelation(jCas);
+// relation.setArg1(arg1);
+// relation.setArg2(arg2);
+// relation.setCategory("BEFORE");
+// arg1.addToIndexes();
+// arg2.addToIndexes();
+// relation.addToIndexes();
+// before.put(childA, childB);
+// }
+// }
+// }
+// //add ends-on A
+// for (Annotation endsOnA : endson.get(argA)) {
+// if (!before.containsEntry(endsOnA, argB)) {
+// //create a new before relation:
+// RelationArgument arg1 = new RelationArgument(jCas);
+// arg1.setArgument(endsOnA);
+// RelationArgument arg2 = new RelationArgument(jCas);
+// arg2.setArgument(argB);
+// BinaryTextRelation relation = new BinaryTextRelation(jCas);
+// relation.setArg1(arg1);
+// relation.setArg2(arg2);
+// relation.setCategory("BEFORE");
+// arg1.addToIndexes();
+// arg2.addToIndexes();
+// relation.addToIndexes();
+// before.put(endsOnA, argB);
+// }
+// }
+// //add begins-on B
+// for (Annotation beginsOnB : beginson.get(argB)) {
+// if (!before.containsEntry(argA, beginsOnB)) {
+// //create a new before relation:
+// RelationArgument arg1 = new RelationArgument(jCas);
+// arg1.setArgument(argA);
+// RelationArgument arg2 = new RelationArgument(jCas);
+// arg2.setArgument(beginsOnB);
+// BinaryTextRelation relation = new BinaryTextRelation(jCas);
+// relation.setArg1(arg1);
+// relation.setArg2(arg2);
+// relation.setCategory("BEFORE");
+// arg1.addToIndexes();
+// arg2.addToIndexes();
+// relation.addToIndexes();
+// before.put(argA, beginsOnB);
+// }
+// }
+// }
+// }
+//
+// }
}
Added: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/AnnotationIdCollection.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/AnnotationIdCollection.java?rev=1588359&view=auto
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/AnnotationIdCollection.java (added)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/AnnotationIdCollection.java Thu Apr 17 20:12:28 2014
@@ -0,0 +1,160 @@
+package org.apache.ctakes.temporal.utils;
+
+import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
+import org.apache.uima.jcas.tcas.Annotation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 6/17/13
+ */
+public class AnnotationIdCollection {
+
+ static public final int NO_ENTITY_ID = Integer.MIN_VALUE;
+
+
+ // Key = Annotation (named, event, timex), Value = id number for each "unique" reference.
+ // Co-referent entities will have the same id number
+ private final Map<Annotation,Integer> _entityIdMap;
+ // Key = id number for each "unique" reference, value = primary entity
+ private final Map<Integer,Annotation> _idAnnotationMap;
+
+
+ public AnnotationIdCollection(ArrayList<BinaryTextRelation> temporalRelation){ //final AnnotationCollection annotationCollection ) {
+ _entityIdMap = new HashMap<Annotation, Integer>();
+ _idAnnotationMap = new HashMap<Integer, Annotation>();
+
+ Set<Annotation> allAnnotations = new HashSet<Annotation>();
+ for (BinaryTextRelation relation : temporalRelation) {
+ allAnnotations.add(relation.getArg1().getArgument());
+ allAnnotations.add(relation.getArg2().getArgument());
+ }
+ final List<Annotation> annotationsList = new ArrayList<Annotation>( allAnnotations );
+ Collections.sort( annotationsList, ArgComparator.INSTANCE );// just so that closure counts are consistent
+
+ int id = 0;
+ for (Annotation annotation : annotationsList) {
+ _entityIdMap.put( annotation, id );
+ _idAnnotationMap.put( id, annotation );
+ id++;
+ }
+
+ // int id = 0;
+ // for ( Annotation entity : annotationCollection.getNamedEntities() ) {
+ // _entityIdMap.put( entity, id );
+ // _idAnnotationMap.put( id, entity );
+ // id++;
+ // }
+ // for ( Annotation entity : annotationCollection.getTimes() ) {
+ // _entityIdMap.put( entity, id );
+ // _idAnnotationMap.put( id, entity );
+ // id++;
+ // }
+ // for ( Annotation entity : annotationCollection.getEvents() ) {
+ // _entityIdMap.put( entity, id );
+ // _idAnnotationMap.put( id, entity );
+ // id++;
+ // }
+ // for ( CoreferenceChain chain : annotationCollection.getCoreferenceEntities() ) {
+ // for ( Annotation entity : chain ) {
+ // _entityIdMap.put( entity, id );
+ // }
+ // _entityIdMap.put( chain, id );
+ // _idAnnotationMap.put( id, chain );
+ // id++;
+ // }
+
+ }
+
+
+ /**
+ * @return a collection of unique ids for all unique entities
+ */
+ public Set<Integer> getAnnotationIds() {
+ // return Collections.unmodifiableSet( _idAnnotationMap.keySet() );
+ return Collections.unmodifiableSet( new HashSet<Integer>( _entityIdMap.values() ) );
+ }
+
+ /**
+ * @param entity some entity, be it unique on its own or part of a coreference chain
+ * @return an id for the entity
+ */
+ public int getAnnotationId( final Annotation entity ) {
+ final Integer id = _entityIdMap.get( entity );
+ if ( id != null ) {
+ return id;
+ }
+ return getIdByAnnotationEqual( entity );
+ }
+
+ private int getIdByAnnotationEqual( final Annotation entity ) {
+ for ( Annotation referenceAnnotation : _entityIdMap.keySet() ) {
+ if ( referenceAnnotation.equals( entity ) ) {
+ final int id = _entityIdMap.get( referenceAnnotation );
+ // Prevent future iteration searches
+ _entityIdMap.put( entity, id );
+ return id;
+ }
+ }
+ return getIdByTextSpan( entity.getBegin(), entity.getEnd() );
+ }
+
+ private int getIdByTextSpan( final int begin, int end ) {
+ for ( Annotation referenceAnnotation : _entityIdMap.keySet() ) {
+ if ( referenceAnnotation.getBegin()==begin && referenceAnnotation.getEnd()==end){//.getTextSpan().equals( textSpan ) ) {
+ return _entityIdMap.get( referenceAnnotation );
+ }
+// // TODO necessary?
+// if ( referenceAnnotation instanceof CoreferenceChain ) {
+// for ( Annotation coreference : (CoreferenceChain)referenceAnnotation ) {
+// if ( coreference.getTextSpan().equals( textSpan ) ) {
+// return _entityIdMap.get( referenceAnnotation );
+// }
+// }
+// }
+ }
+ return NO_ENTITY_ID;
+ }
+
+
+ /**
+ * @param entityId some id
+ * @return the NamedAnnotation, Event, Timex, or CoreferenceChain with the given referenceId
+ */
+ public Annotation getAnnotation( final int entityId ) {
+ return _idAnnotationMap.get( entityId );
+ }
+
+ public Annotation getAnnotation( final Annotation entity ) {
+ final int id = getAnnotationId( entity );
+ if ( id != NO_ENTITY_ID ) {
+ return getAnnotation( id );
+ }
+ return null;
+ }
+
+
+ static private enum ArgComparator implements Comparator<Annotation> {
+ INSTANCE;
+ /**
+ * {@inheritDoc}
+ */
+ public int compare( final Annotation arg1, final Annotation arg2 ) {
+ final int startDiff = arg1.getBegin() - arg2.getBegin();
+ if ( startDiff != 0 ) {
+ return startDiff;
+ }
+ return arg1.getEnd() - arg2.getEnd();
+ }
+ }
+
+}
Propchange: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/AnnotationIdCollection.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TLinkTypeArray2.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TLinkTypeArray2.java?rev=1588359&view=auto
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TLinkTypeArray2.java (added)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TLinkTypeArray2.java Thu Apr 17 20:12:28 2014
@@ -0,0 +1,477 @@
+package org.apache.ctakes.temporal.utils;
+
+import org.apache.ctakes.temporal.utils.AnnotationIdCollection;
+import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
+import org.apache.ctakes.typesystem.type.relation.RelationArgument;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.tcas.Annotation;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.ctakes.temporal.utils.TlinkType.AFTER;
+import static org.apache.ctakes.temporal.utils.TlinkType.BEFORE;
+import static org.apache.ctakes.temporal.utils.TlinkType.BEGINS_ON;
+import static org.apache.ctakes.temporal.utils.TlinkType.CONTAINS;
+import static org.apache.ctakes.temporal.utils.TlinkType.ENDS_ON;
+import static org.apache.ctakes.temporal.utils.TlinkType.OVERLAP;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 6/18/13
+ */
+public class TLinkTypeArray2 {
+
+ // given relation A to B and relation B to C, return relation A to C
+
+ /**
+ * @param tlinkTypesAtoB for a relation with an end argument coincidental with (relationType23's relation), the store
+ * @param tlinkTypesBtoC for a relation with a start argument coincidental with (relationType12's relation), the store
+ * @return for a relation with the start argument of (relationTypeAtoB's relations) and the end argument of
+ * (relationTypeBtoC's relations), the set of time relations if one can be derived from the first two other sets, else null
+ */
+ static private TlinkTypeSet getTlinkTypesAtoC( final TlinkTypeSet tlinkTypesAtoB,
+ final TlinkTypeSet tlinkTypesBtoC ) {
+ if ( tlinkTypesAtoB == null || tlinkTypesBtoC == null
+ || tlinkTypesAtoB.isEmpty() || tlinkTypesBtoC.isEmpty() ) {
+ return null;
+ }
+ final TlinkTypeSet tlinkTypeSetAtoC = new TlinkTypeSet();
+ for ( TlinkType tlinkTypeAtoB : tlinkTypesAtoB ) {
+ for ( TlinkType tlinkTypeBtoC : tlinkTypesBtoC ) {
+ final TlinkType tertiary = tlinkTypeAtoB.getTimeRelationTypeAtoC( tlinkTypeBtoC );
+ if ( tertiary != null ) {
+ tlinkTypeSetAtoC.add( tertiary );
+ }
+ }
+ }
+ return tlinkTypeSetAtoC;
+ }
+
+
+
+ // Array of relation types for each event/time to other event/time
+ private final TlinkTypeSet[][] _tlinkTypesArray;
+ // map of entity ids in relations and their corresponding column/row indices in _tlinkTypesArray
+ // Key = entity id, Value = column/row index
+// private final Map<Integer, Integer> _entityIdIndices;
+
+ private final AnnotationIdCollection _entityIdCollection;
+ private final List<Integer> _entityIdList;
+
+// public TLinkTypeArray2( final AnnotationCollection annotationCollection ) {
+// this( annotationCollection.getTimeRelations(), annotationCollection.getReferenceCollection() );
+// }
+
+ public TLinkTypeArray2( final List<BinaryTextRelation> tlinkList, final AnnotationIdCollection entityIdCollection ) {
+ final Set<Integer> tlinkAnnotationIds = new HashSet<Integer>();
+ for ( BinaryTextRelation tlink : tlinkList ) {
+ // Add all entities, even for relations that have no valid relation type
+ tlinkAnnotationIds.add( entityIdCollection.getAnnotationId( tlink.getArg1().getArgument() ) );
+ tlinkAnnotationIds.add( entityIdCollection.getAnnotationId( tlink.getArg2().getArgument() ) );
+ }
+ _entityIdList = new ArrayList<Integer>( tlinkAnnotationIds );
+ Collections.sort( _entityIdList ); // just so that -reported- closure counts are consistent
+ final int entityCount = _entityIdList.size();
+ _tlinkTypesArray = new TlinkTypeSet[entityCount][entityCount];
+ _entityIdCollection = entityIdCollection;
+ populateTlinkTypesArray( tlinkList );
+ }
+
+ public TlinkTypeSet getTlinkTypes( final BinaryTextRelation tlink ) {
+ final Annotation entityA = tlink.getArg1().getArgument();
+ final Annotation entityB = tlink.getArg2().getArgument();
+ final int entityIdA = _entityIdCollection.getAnnotationId( entityA );
+ final int entityIdB = _entityIdCollection.getAnnotationId( entityB );
+ final int indexA = _entityIdList.indexOf( entityIdA );
+ final int indexB = _entityIdList.indexOf( entityIdB );
+ return getTlinkTypes( indexA, indexB );
+ }
+
+ public List<BinaryTextRelation> getClosedTlinks(JCas jCas) {
+ final int length = getAnnotationIdCount();
+ if ( length == 0 ) {
+ return Collections.emptyList();
+ }
+ final List<BinaryTextRelation> closedTlinks = new ArrayList<BinaryTextRelation>();
+ for ( int row = 0; row<length; row++ ) {
+ for ( int column = 0; column<length; column++ ) {
+ if ( row == column ) {
+ continue;
+ }
+ final TlinkTypeSet tlinkTypeSet = _tlinkTypesArray[row][column];
+ if ( tlinkTypeSet == null || tlinkTypeSet.isEmpty() ) {
+ continue;
+ }
+ for ( TlinkType tlinkType : tlinkTypeSet ) {
+ final BinaryTextRelation tlink = createTlink(jCas, row, column, tlinkType );
+ if ( tlink != null ) {
+// System.out.println(row+","+column+" "+tlink.getFirstAnnotation().getSpannedText()+ " " + tlinkType + " " + tlink.getSecondAnnotation().getSpannedText());
+ closedTlinks.add( tlink );
+ }
+ }
+ }
+ }
+ return closedTlinks;
+ }
+
+ private BinaryTextRelation createTlink( final JCas jCas, int row, final int column, final TlinkType tlinkType ) {
+ // final ClassType tlinkClass = new CustomClassType( "TLINK" );
+ final Annotation entityA = getAnnotation( row );
+ final Annotation entityB = getAnnotation( column );
+ if ( entityA == null || entityB == null ) {
+ return null;
+ }
+ // final Attribute tlinkAttribute = tlinkType.getAsAttribute();
+ //// if ( entityB instanceof Timex ) {
+ //// System.out.println( "TRTA2 " + entityA.getSpannedText() + " " + tlinkType.getValue() + " " + entityB.getSpannedText() + " " + timeRelationType );
+ //// }
+ // return new DefaultRelation( entityA, entityB, tlinkClass, "Closure", tlinkAttribute );
+ RelationArgument arg1 = new RelationArgument(jCas);
+ arg1.setArgument(entityA);
+ RelationArgument arg2 = new RelationArgument(jCas);
+ arg2.setArgument(entityB);
+ BinaryTextRelation relation = new BinaryTextRelation(jCas);
+ relation.setArg1(arg1);
+ relation.setArg2(arg2);
+ relation.setCategory(tlinkType.name().replace( "_", "-" ));//check if this is correct
+ return relation;
+ }
+
+ private int getAnnotationId( final int index ) {
+ return _entityIdList.get( index );
+ }
+
+ private Annotation getAnnotation( final int index ) {
+ final int entityId = getAnnotationId( index );
+ return _entityIdCollection.getAnnotation( entityId );
+ }
+
+ // -------------------- Population of array -------------------- //
+
+ private void populateTlinkTypesArray( final List<BinaryTextRelation> tlinkList ) {
+ // initialize array with existing known time relation types
+ int explicitCount = 0;
+ for ( BinaryTextRelation tlink : tlinkList ) {
+ if ( addTlinkType( tlink ) ) {
+ explicitCount += 2;
+ }
+ }
+ // add to array inferred time relation types
+ final int entityIdCount = getAnnotationIdCount();
+ // column
+ int inferredInIteration = -1; // seed
+ int iterations = 0;
+ int totalInferred = 0;
+ while (inferredInIteration != 0 ) {
+ inferredInIteration = 0;
+ for ( int index = 0; index < entityIdCount; index++ ) {
+ inferredInIteration += inferForIndex( index );
+ }
+ totalInferred += inferredInIteration;
+ iterations++;
+ }
+ // TODO What follows is just info
+ int tlinkCount = 0;
+ for ( int i=0; i<entityIdCount; i++ ) {
+ for ( int j=0; j<entityIdCount; j++ ) {
+ if ( _tlinkTypesArray[i][j] != null ) {
+ tlinkCount += _tlinkTypesArray[i][j].size();
+// System.out.println( i+","+j+" " + getAnnotation( i ).getSpannedText() + " " +_tlinkTypesArray[i][j] + " " + getAnnotation( j ).getSpannedText());
+ }
+ }
+ }
+ System.out.println( "===================================================================================");
+ System.out.println( " Marked Entities: " + entityIdCount
+ + ", Marked TLinks: " + tlinkList.size()
+ + ", Proper TLinks: " + explicitCount
+ + ", Inferred TLinks: " + totalInferred
+ + ", Total TLinks: " + tlinkCount
+ + ", Iterations: " + iterations );
+ System.out.println( "===================================================================================");
+ }
+
+
+ private int inferForIndex( final int indexA ) {
+ final int entityIdCount = getAnnotationIdCount();
+ int inferredCount = 0;
+ for ( int indexB = 0; indexB < entityIdCount; indexB++ ) {
+ if ( indexA == indexB ) {
+ continue;
+ }
+ final TlinkTypeSet tlinkTypesAtoB = getTlinkTypes( indexA, indexB );
+ if ( tlinkTypesAtoB == null ) {
+ // No time relation types for cell, can't infer something from nothing, move on
+ continue;
+ }
+ for ( int indexC = 0; indexC < entityIdCount; indexC++ ) {
+ if ( indexC == indexA || indexC == indexB ) {
+ continue;
+ }
+ final TlinkTypeSet tlinkTypesBtoC = getTlinkTypes( indexB, indexC );
+ if ( tlinkTypesBtoC == null ) {
+ // No time relation types for cell, can't infer something from nothing, move on
+ continue;
+ }
+ inferredCount += inferTlinkTypesForIndexAtoBtoC( indexA, indexB, indexC,
+ tlinkTypesAtoB, tlinkTypesBtoC );
+ if ( !hasTlinkType( indexA, indexB, OVERLAP ) ) {
+ // search for overlap between two nodes marked overlap
+ inferredCount += inferTlinkTypesForAnnotationAtoBwithCandD( indexA, indexB, indexC, OVERLAP );
+ }
+ if ( !hasTlinkType( indexA, indexB, CONTAINS ) ) {
+ // search for overlap between two nodes marked contains
+ inferredCount += inferTlinkTypesForAnnotationAtoBwithCandD( indexA, indexB, indexC, CONTAINS );
+ }
+ }
+ }
+ return inferredCount;
+ }
+
+ private int inferTlinkTypesForIndexAtoBtoC( final int indexA, @SuppressWarnings("unused") final int indexB, final int indexC,
+ final TlinkTypeSet tlinkTypesAtoB,
+ final TlinkTypeSet tlinkTypesBtoC ) {
+ int addedCount = 0;
+ final TlinkTypeSet tlinkTypesAtoC = getTlinkTypesAtoC( tlinkTypesAtoB,
+ tlinkTypesBtoC );
+ // // DEBUG
+// final int lastCount = addedCount;
+ // // END DEBUG
+ addedCount += addTlinkTypes( indexA, indexC, tlinkTypesAtoC );
+ // // DEBUG
+// if ( addedCount > lastCount ) {
+// System.out.println( indexA + " " + timeRelationTypesAtoB + " " + indexB + ", "
+// + indexB + " " + timeRelationTypesBtoC + " " + indexC + " "
+// + " ~ " + indexA + " " + timeRelationTypesAtoC + " " + indexC
+// + " & " + indexC + " " + timeRelationTypesAtoC.createReciprocals() + " " + indexA );
+// }
+ // // END DEBUG
+ return addedCount;
+ }
+
+ // search overlap between two nodes marked overlap or contains between two nodes marked contains
+ private int inferTlinkTypesForAnnotationAtoBwithCandD( final int indexA, final int indexB, final int indexC,
+ final TlinkType tlinkType ) {
+ final int entityCount = getAnnotationIdCount();
+ int addedCount = 0;
+ // if A ov C && A ov D, C < B || C eo B, B < D || D bo B, then A ov B ( A ov C < B < D ov A )
+ // if A cn C && A cn D, (C < B || C eo B), (B < D || D bo B), then A cn B ( A cn C < B < D cn A )
+ if ( hasTlinkType( indexA, indexC, tlinkType ) ) {
+ // A ov C or A cn C
+ for ( int indexD = 0; indexD < entityCount; indexD++ ) {
+ if ( indexD == indexA || indexD == indexB || indexD == indexC ) {
+ continue;
+ }
+ if ( hasTlinkType( indexA, indexD, tlinkType ) ) {
+ // A ov D or A cn D
+ // TODO This needs to be changed so two before/after make a contained and begins/ends-on makes overlap
+ if ( (hasTlinkType( indexB, indexC, AFTER )
+ || hasTlinkType( indexB, indexC, BEGINS_ON ))
+ && (hasTlinkType( indexB, indexD, BEFORE )
+ || hasTlinkType( indexB, indexD, ENDS_ON )) ) {
+ // A ov C < B < D ov A, therefore A ov B or A cn C < B < D cn A, therefore A cn B
+ if ( addTlinkType( indexA, indexB, tlinkType ) ) {
+ addedCount++;
+ }
+ }
+ }
+ }
+ }
+ return addedCount;
+ }
+
+
+ private boolean isIndexOk( final int entityIndex ) {
+ return entityIndex >= 0 && entityIndex < getAnnotationIdCount();
+ }
+
+ private int getAnnotationIdCount() {
+ return _entityIdList.size();
+ }
+
+ private boolean hasTlinkType( final int indexA, final int indexB,
+ final TlinkType tlinkType ) {
+ if ( indexA == indexB ) {
+ // entities are the same, therefore no relationship
+ return false;
+ }
+ final TlinkTypeSet tlinkTypes = getTlinkTypes( indexA, indexB );
+ return tlinkTypes != null && tlinkTypes.contains( tlinkType );
+ }
+
+ private TlinkTypeSet getTlinkTypes( final int indexA, final int indexB ) {
+ if ( indexA == indexB || !isIndexOk( indexA ) || !isIndexOk( indexB ) ) {
+ return null;
+ }
+ return _tlinkTypesArray[indexA][indexB];
+ }
+
+ private int addTlinkTypes( final int indexA, final int indexC,
+ final TlinkTypeSet tlinkTypes ) {
+ if ( tlinkTypes == null || tlinkTypes.isEmpty()
+ || !isIndexOk( indexA ) || !isIndexOk( indexC ) ) {
+ return 0;
+ }
+ if ( _tlinkTypesArray[indexA][indexC] == null ) {
+ _tlinkTypesArray[indexA][indexC] = tlinkTypes;
+ _tlinkTypesArray[indexC][indexA] = tlinkTypes.createReciprocals();
+ return 2;
+ }
+ int addedCount = 0;
+ if ( _tlinkTypesArray[indexC][indexA] == null ) {
+ _tlinkTypesArray[indexC][indexA] = new TlinkTypeSet();
+ }
+ for ( TlinkType tlinkType : tlinkTypes ) {
+// if ( getAnnotation(indexC) instanceof Timex && getAnnotation(indexA) instanceof Timex ) {
+// System.out.println( getAnnotation(indexA).getSpannedText() + " " + relationType + " " + getAnnotation(indexC).getSpannedText() );
+// }
+ boolean added = _tlinkTypesArray[indexA][indexC].add( tlinkType );
+ if ( added ) {
+ addedCount++;
+ }
+ added = _tlinkTypesArray[indexC][indexA].add( tlinkType.getReciprocal() );
+ if ( added ) {
+ addedCount++;
+ }
+ }
+ return addedCount;
+ }
+
+
+
+
+
+ /////////// Add TlinkType /////////////
+
+ private boolean addTlinkType( final BinaryTextRelation tlink ) {
+ // Checked and ok 7/10/13 spf
+ final TlinkType tlinkType = TlinkType.getTlinkType( tlink );
+ if ( tlinkType == null ) {
+ return false;
+ }
+ final boolean added1 = addTlinkType( tlink.getArg1().getArgument(), tlink.getArg2().getArgument(),
+ tlinkType );
+ // Add reciprocal
+ final boolean added2 = addTlinkType( tlink.getArg2().getArgument(), tlink.getArg1().getArgument(),
+ tlinkType.getReciprocal() );
+ return added1 || added2;
+ }
+
+ private boolean addTlinkType( final Annotation entityA, final Annotation entityB,
+ final TlinkType tlinkType ) {
+ // Checked and ok 7/12/13 spf
+ final int entityIdA = _entityIdCollection.getAnnotationId( entityA );
+ final int entityIdB = _entityIdCollection.getAnnotationId( entityB );
+ return addTlinkType( entityIdA, entityIdB, tlinkType );
+ }
+
+ private boolean addTlinkType( final int entityIdA, final int entityIdB,
+ final TlinkType tlinkType ) {
+ // Checked and ok 7/12/13 spf
+ final int indexA = _entityIdList.indexOf( entityIdA );
+ final int indexB = _entityIdList.indexOf( entityIdB );
+ if ( tlinkType == null || !isIndexOk( indexA ) || !isIndexOk( indexB ) ) {
+ return false;
+ }
+ if ( _tlinkTypesArray[indexA][indexB] == null ) {
+ _tlinkTypesArray[indexA][indexB] = new TlinkTypeSet();
+ }
+ return _tlinkTypesArray[indexA][indexB].add( tlinkType );
+ }
+
+
+
+
+//
+// // for testing
+// static private final String XML_UMLS_FILE_PATH
+// = "C:\\Spiffy\\Data\\THYME2\\Gold\\UMLS\\set08\\ID008_clinic_024.knowtator.xml";
+// static private final String XML_THYME_FILE_PATH
+// = "C:\\Spiffy\\Data\\THYME2\\Gold\\THYME\\Set08\\ID008_clinic_024.knowtator.xml";
+// static private final String XML_CHAIN_FILE_PATH
+// = "C:\\Spiffy\\Data\\THYME2\\Gold\\THYME_Chains\\Set08\\ID008_clinic_024.chains";
+//
+//
+// static private AnnotationCollection getAnnotationCollection( final String filePath ) {
+// final KnowtatorXmlParser xmlParser = new KnowtatorXmlParser();
+// xmlParser.parseFile( filePath );
+// return xmlParser.getAnnotationCollection();
+// }
+//
+// static private java.util.List<CoreferenceChain> getCoreferenceCollection( final String filePath,
+// final Collection<Event> eventCollection,
+// final Collection<Annotation> entityCollection ) {
+// final java.util.List<Set<TextSpan>> textSpanChains = new ArrayList<Set<TextSpan>>();
+// try {
+// final BufferedReader reader = new BufferedReader( new FileReader( filePath ) );
+// String line = reader.readLine();
+// while ( line != null ) {
+// final Set<TextSpan> textSpans = new HashSet<TextSpan>();
+// final String[] indicesArray = line.split( "\\s+" );
+// for ( String textSpanIndices : indicesArray ) {
+// final String[] indices = textSpanIndices.split( "-" );
+// final int start = Integer.parseInt( indices[0] );
+// final int end = Integer.parseInt( indices[1] );
+// textSpans.add( new DefaultTextSpan( start, end ) );
+// }
+// textSpanChains.add( textSpans );
+// line = reader.readLine();
+// }
+// } catch ( IOException ioE ) {
+// System.err.println( "Couldn't read coreference chain file " + filePath );
+// System.err.println( ioE.getMessage() );
+// return Collections.emptyList();
+// }
+//
+// final Set<CoreferenceChain> chains = new HashSet<CoreferenceChain>();
+// for ( Set<TextSpan> textSpanChain : textSpanChains ) {
+// final HashSet<Annotation> entitySet = new HashSet<Annotation>(0);
+// for ( TextSpan elementSpan : textSpanChain ) {
+// for ( Event event : eventCollection ) {
+// final TextSpan overlapSpan = elementSpan.getIntersectionSpan( event.getTextSpan() );
+// if ( overlapSpan != null && overlapSpan.getLength() > 0 ) {
+// entitySet.add( event );
+// }
+// }
+// for ( Annotation entity : entityCollection ) {
+// final TextSpan overlapSpan = elementSpan.getIntersectionSpan( entity.getTextSpan() );
+// if ( overlapSpan != null && overlapSpan.getLength() > 0 ) {
+// entitySet.add( entity );
+// }
+// }
+// }
+// if ( entitySet.size() > 1 ) {
+// chains.add( new DefaultAnnotationChain( "TLinkTypeArray2", entitySet.toArray( new Annotation[entitySet.size()] ) ) );
+// }
+// }
+//
+// return new ArrayList<CoreferenceChain>( chains );
+// }
+//
+//
+// public static void main( String[] args ) {
+// final AnnotationCollection thymeAnnotationCollection = getAnnotationCollection( XML_THYME_FILE_PATH );
+// final AnnotationCollection umlsAnnotationCollection = getAnnotationCollection( XML_UMLS_FILE_PATH );
+// final java.util.List<CoreferenceChain> coreferenceChains = getCoreferenceCollection( XML_CHAIN_FILE_PATH,
+// thymeAnnotationCollection.getEvents(),
+// umlsAnnotationCollection.getNamedEntities() );
+// final AnnotationCollection coreferenceCollection
+// = new ImmutableAnnotationCollection.AnnoteCollectBuilder().coreferenceChains( coreferenceChains ).build();
+//
+// final java.util.List<AnnotationCollection> annotationCollectionList = new ArrayList<AnnotationCollection>( 2 );
+// annotationCollectionList.add( thymeAnnotationCollection );
+// annotationCollectionList.add( umlsAnnotationCollection );
+// annotationCollectionList.add( coreferenceCollection );
+// final AnnotationCollection annotationCollection
+// = new ImmutableAnnotationCollection.AnnoteCollectMerger().all( annotationCollectionList ).build();
+//
+// new TLinkTypeArray2( annotationCollection );
+// }
+
+
+}
Propchange: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TLinkTypeArray2.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TimeRelationConstants.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TimeRelationConstants.java?rev=1588359&view=auto
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TimeRelationConstants.java (added)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TimeRelationConstants.java Thu Apr 17 20:12:28 2014
@@ -0,0 +1,17 @@
+package org.apache.ctakes.temporal.utils;
+
+/**
+ * Author: SPF
+ * Affiliation: CHIP-NLP
+ * Date: 4/17/13
+ */
+public interface TimeRelationConstants {
+ int NO = -1;
+ int BF = 0;
+ int AF = 1;
+ int CN = 2;
+ int CB = 3;
+ int BO = 4;
+ int EO = 5;
+ int OV = 6;
+}
Propchange: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TimeRelationConstants.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkType.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkType.java?rev=1588359&view=auto
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkType.java (added)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkType.java Thu Apr 17 20:12:28 2014
@@ -0,0 +1,261 @@
+package org.apache.ctakes.temporal.utils;
+
+import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
+
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.AF;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.BF;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.BO;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.CB;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.CN;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.EO;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.NO;
+import static org.apache.ctakes.temporal.utils.TimeRelationConstants.OV;
+
+/**
+ * Enumeration of the three temporal relation types used in THYME (before, overlap, contains)
+ * and their reciprocals (after, overlap, contained_by)
+ * Begins-on and Ends-on added 4-11-2013
+ */
+public enum TlinkType {
+ BEFORE( BF ), // A+ < B- where + is end, - is start
+ AFTER( AF ), // A- > B+
+ OVERLAP( OV ), // A- < B- < A+ || B- < A- < B+
+ CONTAINS( CN ), // A- < B- && A+ > B+
+ CONTAINED_BY( CB ), // A- > B- && A+ < B+
+ BEGINS_ON( BO ), // A- = B+
+ ENDS_ON( EO ); // A+ = B-
+// INITIATES( IN )
+// CONTINUES( CT )
+// REINITIATES( RE )
+
+ // TODO refactor to use TlinkAttributeValue enum
+
+ static public TlinkType getTlinkType( final BinaryTextRelation tlink ) {
+ final String type = tlink.getCategory();
+ if ( type == null ) {
+ return null;
+ }
+ return getTimeRelationType( type );
+ }
+
+ static public TlinkType getTimeRelationType( final String name ) {
+ final String upper = name.toUpperCase().replace( "_", "-" );
+ if ( upper.equals( "BEFORE" ) ) {
+ return BEFORE;
+ } else if ( upper.equals( "AFTER" ) ) {
+ return AFTER; // Special case for symmetry
+ } else if ( upper.equals( "OVERLAP" ) || upper.equals( "UNDEFINED" ) || upper.isEmpty() ) {
+ return OVERLAP;
+ } else if ( upper.equals( "CONTAINS" ) ) {
+ return CONTAINS;
+ } else if ( upper.equals( "CONTAINED-BY" ) ) {
+ return CONTAINED_BY; // Special case for symmetry
+// } else if ( upper.equals( "BEGINS-ON" ) ) {
+ } else if ( upper.equals( "BEGINS-ON" ) || upper.equals( "CONTINUES" ) || upper.equals( "TERMINATES" ) ) {
+ return BEGINS_ON;
+// } else if ( upper.equals( "ENDS-ON" ) ) {
+ } else if ( upper.equals( "ENDS-ON" ) || upper.equals( "INITIATES" ) || upper.equals( "REINITIATES" ) ) {
+ return ENDS_ON;
+ }
+ return null;
+ }
+
+ static public TlinkType getTimeRelationType( final long startA, final long startB,
+ final long endA, final long endB ) {
+ if ( endA < startB ) {
+ return BEFORE;
+ } else if ( startA > endB ) {
+ return AFTER;
+ } else if ( endA == startB ) {
+ return ENDS_ON;
+ } else if ( startA == endB ) {
+ return BEGINS_ON;
+ }
+ final long startCompare = startA - startB;
+ final long endCompare = endA - endB;
+ if ( startCompare < 0 && endCompare > 0 ) {
+ return CONTAINS;
+ } else if ( startCompare > 0 && endCompare < 0 ) {
+ return CONTAINED_BY;
+ } else if ( startCompare == 0 && endCompare > 0 ) {
+ return BEGINS_ON;
+ } else if ( startCompare < 0 && endCompare == 0 ) {
+ return ENDS_ON;
+ }
+ return OVERLAP;
+ }
+
+ static public TlinkType getCombinedTypeConservative( final TlinkType typeA,
+ final TlinkType typeB ) {
+ if ( typeA == typeB ) {
+ return typeA;
+ }
+ return OVERLAP;
+ }
+
+ @SuppressWarnings("incomplete-switch")
+static public TlinkType getCombinedTypeLiberal( final TlinkType typeA,
+ final TlinkType typeB ) {
+ if ( typeA == typeB ) {
+ return typeA;
+ }
+ if ( typeA == typeB.getReciprocal() ) {
+ return OVERLAP;
+ }
+ switch ( typeA ) {
+ case BEFORE: {
+ switch ( typeB ) {
+ case CONTAINS: return ENDS_ON;
+ case CONTAINED_BY: return ENDS_ON;
+ case BEGINS_ON: return CONTAINS;
+ case ENDS_ON: return ENDS_ON;
+ case OVERLAP: return ENDS_ON;
+ }
+ }
+ case AFTER: {
+ switch ( typeB ) {
+ case CONTAINS: return BEGINS_ON;
+ case CONTAINED_BY: return BEGINS_ON;
+ case BEGINS_ON: return BEGINS_ON;
+ case ENDS_ON: return CONTAINS;
+ case OVERLAP: return BEGINS_ON;
+ }
+ }
+ case CONTAINS: {
+ switch ( typeB ) {
+ case BEGINS_ON: return BEGINS_ON;
+ case ENDS_ON: return ENDS_ON;
+ case OVERLAP: return CONTAINS;
+ }
+ }
+ case CONTAINED_BY: {
+ switch ( typeB ) {
+ case BEGINS_ON: return BEGINS_ON;
+ case ENDS_ON: return ENDS_ON;
+ case OVERLAP: return CONTAINED_BY;
+ }
+ }
+ case OVERLAP: {
+ switch ( typeB ) {
+ case BEGINS_ON: return BEGINS_ON;
+ case ENDS_ON: return ENDS_ON;
+ }
+ }
+ }
+ return getCombinedTypeLiberal( typeB, typeA );
+ }
+
+
+ static private TlinkType getTimeRelationType( final int index ) {
+ switch ( index ) {
+ case BF : return BEFORE;
+ case AF : return AFTER;
+ case CN : return CONTAINS;
+ case CB : return CONTAINED_BY;
+ case BO : return BEGINS_ON;
+ case EO : return ENDS_ON;
+ case OV : return OVERLAP;
+ }
+ return null;
+ }
+
+ // Given relation A to B and relation B to C, return relation A to C
+ // This is a very conservative interpretation.
+ // There are several OV possibilities that are left out because CN is an equal possibility
+// static private final int[][] TML_ABC_ARRAY =
+// //BF, AF, CN, CB, BO, EO, OV A to B
+// {{BF, NO, NO, BF, NO, BF, NO}, // BF
+// {NO, AF, NO, AF, AF, NO, NO}, // AF
+// {BF, AF, CN, NO, AF, BF, NO}, // CN
+// {NO, NO, OV, CB, NO, NO, NO}, // CB B to C
+// {NO, AF, NO, AF, AF, OV, NO}, // BO
+// {BF, NO, NO, BF, OV, BF, NO}, // EO
+// {NO, NO, NO, NO, NO, NO, NO}}; // OV then A to C
+
+// static private final int[][] TML_ABC_ARRAY =
+// //BF, AF, CN, CB, BO, EO, OV A to B
+// {{BF, NO, NO, BF, NO, BF, NO}, // BF
+// {NO, AF, NO, AF, AF, NO, NO}, // AF
+// {BF, AF, CN, NO, AF, BF, NO}, // CN
+// {NO, NO, OV, CB, OV, OV, OV}, // CB B to C
+// {NO, AF, OV, AF, AF, OV, NO}, // BO
+// {BF, AF, OV, BF, OV, BF, NO}, // EO
+// {NO, NO, OV, NO, NO, NO, NO}}; // OV then A to C
+
+ static private final int[][] TML_ABC_ARRAY =
+ //BF, AF, CN, CB, BO, EO, OV A to B
+ {{BF, NO, NO, BF, NO, BF, NO}, // BF
+ {NO, AF, NO, AF, AF, NO, NO}, // AF
+ {BF, AF, CN, NO, AF, BF, NO}, // CN
+ {NO, NO, OV, CB, OV, OV, OV}, // CB B to C
+ {NO, AF, NO, AF, AF, OV, NO}, // BO
+ {BF, AF, NO, BF, OV, BF, NO}, // EO
+ {NO, NO, OV, NO, NO, NO, NO}}; // OV then A to C
+
+ final private int _index;
+
+ private TlinkType( final int index ) {
+ _index = index;
+ }
+
+ private int getIndex() {
+ return _index;
+ }
+
+ /**
+ * @param tlinkTypeBtoC a relation with a start argument coincidental with this relation
+ * @return for this relation A to B and the given relation B to C, return relation A to C
+ */
+ public TlinkType getTimeRelationTypeAtoC( final TlinkType tlinkTypeBtoC ) {
+ // The array elements are fetched [row][column]
+ // Checked and works 7/10/13 spf
+ final int relationIndex = TML_ABC_ARRAY[tlinkTypeBtoC.getIndex()][getIndex()];
+// System.out.println( "A " + toString() + " B and B " + relationTypeBtoC + " C so A " + getTlinkType( relationIndex ) + " C");
+ return getTimeRelationType( relationIndex );
+ }
+
+ /**
+ * @return the reciprocal Temporal Relation type of (this) relation type
+ */
+ public TlinkType getReciprocal() {
+ switch ( this ) {
+ case BEFORE:
+ return AFTER;
+ case AFTER:
+ return BEFORE;
+ case OVERLAP:
+ return OVERLAP;
+ case CONTAINS:
+ return CONTAINED_BY;
+ case CONTAINED_BY:
+ return CONTAINS;
+ case BEGINS_ON:
+ return ENDS_ON;
+ case ENDS_ON:
+ return BEGINS_ON;
+ }
+ return null;
+ }
+
+// public Attribute getAsAttribute() {
+// final String attributeValue = getAttributeValue( this );
+// return new DefaultAttribute( DefinedAttributeType.RELATION_TYPE, attributeValue );
+// }
+
+// static private String getAttributeValue( final TlinkType tlinkType ) {
+// switch ( tlinkType ) {
+// case BEFORE: return "BEFORE";
+// case AFTER : return "AFTER";
+// case OVERLAP : return "OVERLAP";
+// case CONTAINS: return "CONTAINS";
+// case CONTAINED_BY: return "CONTAINED-BY";
+// case BEGINS_ON: return "BEGINS-ON";
+// case ENDS_ON: return "ENDS-ON";
+// }
+// return null;
+// }
+
+
+
+
+}
Propchange: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkType.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkTypeSet.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkTypeSet.java?rev=1588359&view=auto
==============================================================================
--- ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkTypeSet.java (added)
+++ ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkTypeSet.java Thu Apr 17 20:12:28 2014
@@ -0,0 +1,109 @@
+package org.apache.ctakes.temporal.utils;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+* Author: SPF
+* Affiliation: CHIP-NLP
+* Date: 4/17/13
+*/
+public class TlinkTypeSet implements Iterable<TlinkType> {
+
+ private Set<TlinkType> _tlinkTypes;
+
+ public boolean add( final TlinkType tlinkType ) {
+ if ( _tlinkTypes == null ) {
+ _tlinkTypes = new HashSet<TlinkType>( 1 );
+ }
+ return _tlinkTypes.add( tlinkType );
+ }
+
+ public int size() {
+ return _tlinkTypes == null ? 0 : _tlinkTypes.size();
+ }
+
+ public boolean isEmpty() {
+ return _tlinkTypes == null || _tlinkTypes.isEmpty();
+ }
+
+ public boolean contains( final TlinkType tlinkType ) {
+ return _tlinkTypes != null && _tlinkTypes.contains( tlinkType );
+ }
+
+ public TlinkTypeSet createReciprocals() {
+ final TlinkTypeSet reciprocals = new TlinkTypeSet();
+ for ( TlinkType tlinkType : this ) {
+ reciprocals.add( tlinkType.getReciprocal() );
+ }
+ return reciprocals;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @return "NONE," if empty, else a series of & separated time relation type names
+ */
+ @Override
+ public String toString() {
+ if ( isEmpty() ) {
+ return "NONE,";
+ }
+ final StringBuilder sb = new StringBuilder();
+ for ( TlinkType type : _tlinkTypes ) {
+ sb.append( type.name() ).append( " & " );
+ }
+ sb.setLength( sb.length()-3 );
+ sb.append( "," );
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<TlinkType> iterator() {
+ if ( isEmpty() ) {
+ return EMPTY_ITERATOR;
+ }
+ return _tlinkTypes.iterator();
+ }
+
+ static private final Iterator<TlinkType> EMPTY_ITERATOR = new Iterator<TlinkType>() {
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public TlinkType next() {
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ }
+ };
+
+
+
+ // /**
+ // * Agreement between two Time Relation sets.
+ // * 0 indicates no agreement, 1 indicates perfect agreement, anything between indicates partial agreement.
+ // * @param otherTimeRelationTypes time relation type set to contrast with this one
+ // * @return fraction of agreement: # common time relations(*2) divided by # total time relations
+ // */
+ // public double contrast( final TlinkTypeSet otherTimeRelationTypes ) {
+ // if ( otherTimeRelationTypes == null || isEmpty() || otherTimeRelationTypes.isEmpty() ) {
+ // return 0d;
+ // }
+ // final int total = size() + otherTimeRelationTypes.size();
+ // final Set<TlinkType> commonSet = new HashSet<TlinkType>( _tlinkTypes );
+ // commonSet.retainAll( otherTimeRelationTypes._tlinkTypes );
+ // return 2d * (double) commonSet.size() / (double) total;
+ // }
+
+
+
+}
Propchange: ctakes/trunk/ctakes-temporal/src/main/java/org/apache/ctakes/temporal/utils/TlinkTypeSet.java
------------------------------------------------------------------------------
svn:mime-type = text/plain