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.Collection;
031 import java.util.HashSet;
032 import java.util.Set;
033
034 import edu.uchsc.ccp.iaa.Annotation;
035 import edu.uchsc.ccp.iaa.IAA;
036
037 /**
038 * This matcher is very similar to ClassMatcher.
039 *
040 * @author Compaq_Owner
041 *
042 */
043
044 public class SubclassMatcher implements Matcher {
045
046 String className;
047
048 Set<String> subclassNames;
049
050 ClassHierarchy hierarchy;
051
052 public SubclassMatcher(ClassHierarchy hierarchy) {
053 this.hierarchy = hierarchy;
054 }
055
056 /**
057 * This method will return a match from ClassMatcher. If one does not exist,
058 * then match for
059 *
060 *
061 *
062 * Otherwise, null is returned.
063 *
064 * @param annotation
065 * @param compareSetName
066 * @param excludeAnnotations
067 * @param iaa
068 * @param matchResult
069 * will be set to NONTRIVIAL_MATCH, NONTRIVIAL_NONMATCH, or
070 * TRIVIAL_NONMATCH. Trivial non-matches occur when the
071 * annotation is not of the class specified by setIAAClass or a
072 * subclass of it. Trivial non-matches should be ignored and not
073 * counted in any IAA metrics.
074 * @see edu.uchsc.ccp.iaa.matcher.Matcher#match(Annotation, String, Set,
075 * IAA, MatchResult)
076 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#NONTRIVIAL_MATCH
077 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#NONTRIVIAL_NONMATCH
078 * @see edu.uchsc.ccp.iaa.matcher.MatchResult#TRIVIAL_NONMATCH
079 * @see edu.uchsc.ccp.iaa.Annotation#getShortestAnnotation(Collection)
080 * @see #setIAAClass(String)
081 */
082 public Annotation match(Annotation annotation, String compareSetName, Set<Annotation> excludeAnnotations, IAA iaa,
083 MatchResult matchResult) {
084
085 String annotationClassName = annotation.getAnnotationClass();
086 if (!subclassNames.contains(annotationClassName)) {
087 matchResult.setResult(MatchResult.TRIVIAL_NONMATCH);
088 return null;
089 }
090
091 Annotation classMatch = ClassMatcher.match(annotation, compareSetName, iaa, excludeAnnotations);
092 if (classMatch != null) {
093 matchResult.setResult(MatchResult.NONTRIVIAL_MATCH);
094 return classMatch;
095 }
096
097 Set<Annotation> candidateAnnotations = new HashSet<Annotation>();
098 for (String subclassName : subclassNames) {
099 candidateAnnotations.addAll(iaa.getAnnotationsOfClass(subclassName, compareSetName));
100 }
101
102 Set<Annotation> exactlyOverlappingAnnotations = new HashSet<Annotation>(iaa.getExactlyOverlappingAnnotations(
103 annotation, compareSetName));
104 exactlyOverlappingAnnotations.retainAll(candidateAnnotations);
105 exactlyOverlappingAnnotations.removeAll(excludeAnnotations);
106 if (exactlyOverlappingAnnotations.size() > 0) {
107 matchResult.setResult(MatchResult.NONTRIVIAL_MATCH);
108 return exactlyOverlappingAnnotations.iterator().next();
109 }
110
111 Set<Annotation> overlappingAnnotations = new HashSet<Annotation>(iaa.getOverlappingAnnotations(annotation,
112 compareSetName));
113 overlappingAnnotations.retainAll(candidateAnnotations);
114 overlappingAnnotations.removeAll(excludeAnnotations);
115 if (overlappingAnnotations.size() > 0) {
116 matchResult.setResult(MatchResult.NONTRIVIAL_MATCH);
117 if (overlappingAnnotations.size() == 1)
118 return overlappingAnnotations.iterator().next();
119 return Annotation.getShortestAnnotation(overlappingAnnotations);
120 }
121
122 matchResult.setResult(MatchResult.NONTRIVIAL_NONMATCH);
123 return null;
124 }
125
126 /**
127 * Sets the class of the
128 *
129 * @param className
130 */
131 public void setIAAClass(String className) {
132 this.className = className;
133 subclassNames = hierarchy.getSubclasses(className);
134 }
135
136 public String getIAAClass() {
137 return className;
138 }
139
140 public String getName() {
141 return "Subclass matcher for class '" + className + "'";
142 }
143
144 public String getDescription() {
145 return "Two annotations match if their class assignments are equal to '" + className + "' or a subclass of '"
146 + className + "' and their spans overlap.";
147 }
148
149 public boolean returnsTrivials() {
150 return true;
151 }
152
153 public Set<String> getSubclasses() {
154 return hierarchy.getSubclasses(className);
155 }
156 }