001 /*
002 * The contents of this file are subject to the Mozilla Public
003 * License Version 1.1 (the "License"); you may not use this file
004 * except in compliance with the License. You may obtain a copy of
005 * the License at http://www.mozilla.org/MPL/
006 *
007 * Software distributed under the License is distributed on an "AS
008 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
009 * implied. See the License for the specific language governing
010 * rights and limitations under the License.
011 *
012 * The Original Code is Knowtator.
013 *
014 * The Initial Developer of the Original Code is University of Colorado.
015 * Copyright (C) 2005 - 2008. All Rights Reserved.
016 *
017 * Knowtator was developed by the Center for Computational Pharmacology
018 * (http://compbio.uchcs.edu) at the University of Colorado Health
019 * Sciences Center School of Medicine with support from the National
020 * Library of Medicine.
021 *
022 * Current information about Knowtator can be obtained at
023 * http://knowtator.sourceforge.net/
024 *
025 * Contributor(s):
026 * Philip V. Ogren <philip@ogren.info> (Original Author)
027 */
028 package edu.uchsc.ccp.iaa.matcher;
029
030 import java.util.ArrayList;
031 import java.util.HashSet;
032 import java.util.List;
033 import java.util.Set;
034
035 import edu.uchsc.ccp.iaa.Annotation;
036 import edu.uchsc.ccp.iaa.IAA;
037
038 public class SpansExactSimpleFeatureMatcher implements Matcher {
039 // public static final String FEATURE_NAMES =
040 // SpansExactSimpleFeatureMatcher.class.getName()+".FEATURE_NAMES";
041
042 /**
043 * This method will return an annotation that has the exact same spans and
044 * simple features. It is not required that the annotation class match.
045 * Preference will be given to an annotation that has the same class as well
046 * as spans and simple features. If one does not exist, then null is
047 * returned.
048 */
049 public Annotation match(Annotation annotation, String compareSetName, Set<Annotation> excludeAnnotations, IAA iaa,
050 MatchResult matchResult) {
051 return match(annotation, compareSetName, iaa, excludeAnnotations, matchResult);
052 }
053
054 /**
055 * This method will return an annotation that has the exact same spans and
056 * simple features. It is not required that the annotation class match.
057 * Preference will be given to an annotation that has the same class as well
058 * as spans and simple features. If one does not exist, then null is
059 * returned.
060 *
061 * @param annotation
062 * @param compareSetName
063 * @param iaa
064 * @param excludeAnnotations
065 * @param matchResult
066 * will be set to:
067 * <ul>
068 * <li>TRIVIAL_NONMATCH if there are no exactly overlapping
069 * annotations with the passed in annotation
070 * <li>NONTRIVIAL_MATCH if there is an annotation that is exactly
071 * overlapping and the Annotation.compareSimpleFeatures returns
072 * NONTRIVIAL_MATCH
073 * <li>TRIVIAL_MATCH if there is an annotation that is exactly
074 * overlapping and the Annotation.compareSimpleFeatures returns
075 * TRIVIAL_MATCH <br>
076 * Note: if there is a trivial_match then there cannot possibly
077 * be a NONTRIVIAL_MATCH because one of the simple features of
078 * the passed in annotation must have a null value or there are
079 * no simple features.
080 * <li>NONTRIVIAL_NONMATCH if there an annotation that is exactly
081 * overlapping and the Annotation.compareSimpleFeatures returns
082 * NONTRIVIAL_NONMATCH
083 * <li>TRIVIAL_NONMATCH if there is no match or non-trivial
084 * non-match found.
085 * @return will return the first nontrivial match that it finds preferring
086 * @see edu.uchsc.ccp.iaa.matcher.Matcher#match(Annotation, String, Set,
087 * IAA, MatchResult)
088 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#NONTRIVIAL_MATCH
089 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#NONTRIVIAL_NONMATCH
090 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#TRIVIAL_MATCH
091 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#TRIVIAL_NONMATCH
092 */
093
094 public static Annotation match(Annotation annotation, String compareSetName, IAA iaa,
095 Set<Annotation> excludeAnnotations, MatchResult matchResult) {
096 // prefer class and span matches over just span matches
097 Set<Annotation> classAndSpanMatches = ClassAndSpanMatcher.matches(annotation, compareSetName, iaa,
098 excludeAnnotations, false);
099 Set<Annotation> exactlyOverlappingAnnotations = new HashSet<Annotation>(iaa.getExactlyOverlappingAnnotations(
100 annotation, compareSetName));
101 exactlyOverlappingAnnotations.removeAll(classAndSpanMatches);
102 exactlyOverlappingAnnotations.removeAll(excludeAnnotations);
103
104 List<Annotation> candidateAnnotations = new ArrayList<Annotation>(classAndSpanMatches.size()
105 + exactlyOverlappingAnnotations.size());
106 for (Annotation candidateAnnotation : classAndSpanMatches) {
107 candidateAnnotations.add(candidateAnnotation);
108 }
109 for (Annotation candidateAnnotation : exactlyOverlappingAnnotations) {
110 candidateAnnotations.add(candidateAnnotation);
111 }
112
113 boolean nontrivialNonmatch = false;
114
115 for (Annotation candidateAnnotation : candidateAnnotations) {
116 if (!excludeAnnotations.contains(candidateAnnotation)) {
117 int result = Annotation.compareSimpleFeatures(annotation, candidateAnnotation);
118 // if there is a trivial_match then there cannot possibly be a
119 // NONTRIVIAL_MATCH
120 // because one of the simple features of the passed in
121 // annotation must have a null value
122 // or there are no simple features.
123 if (result == MatchResult.NONTRIVIAL_MATCH || result == MatchResult.TRIVIAL_MATCH) {
124 matchResult.setResult(result);
125 return candidateAnnotation;
126 }
127 if (result == MatchResult.NONTRIVIAL_NONMATCH) {
128 nontrivialNonmatch = true;
129 }
130 }
131 }
132
133 if (nontrivialNonmatch)
134 matchResult.setResult(MatchResult.NONTRIVIAL_NONMATCH);
135 else
136 matchResult.setResult(MatchResult.TRIVIAL_NONMATCH);
137 return null;
138 }
139
140 public String getName() {
141 return "Simple slots matcher (with same spans)";
142 }
143
144 public String getDescription() {
145 return "Annotations match if they have the same spans and the same value for simple slots (e.g. slots that are primitive values such as integer and String). Only slots that are specified must match.";
146 }
147
148 public boolean returnsTrivials() {
149 return true;
150 }
151
152 }