Merge branch 'develop' into features/JAL-3010ontologyFeatureSettings
[jalview.git] / src / jalview / datamodel / ontology / OntologyBase.java
1 package jalview.datamodel.ontology;
2
3 import jalview.io.gff.SequenceOntologyFactory;
4 import jalview.io.gff.SequenceOntologyI;
5
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13
14 /**
15  * A base class for models of Sequence Ontology and others
16  * 
17  * @author gmcarstairs
18  *
19  */
20 public abstract class OntologyBase implements OntologyI
21 {
22   protected Map<String, List<String>> rootParents = new HashMap<>();
23
24   @Override
25   public Set<String> getParentTerms(Set<String> terms)
26   {
27     Set<String> parents = new HashSet<>(terms);
28
29     boolean childRemoved = true;
30     while (childRemoved)
31     {
32       childRemoved = removeChild(parents);
33     }
34     return parents;
35   }
36
37   /**
38    * Removes the first term in the given set found which is a child of another
39    * term in the set. Answers true if a child was found and removed, else false.
40    * 
41    * @param terms
42    * @return
43    */
44   boolean removeChild(Set<String> terms)
45   {
46     for (String t1 : terms)
47     {
48       for (String t2 : terms)
49       {
50         if (t1 != t2)
51         {
52           if (isA(t1, t2))
53           {
54             terms.remove(t1);
55             return true;
56           }
57           if (isA(t2, t1))
58           {
59             terms.remove(t2);
60             return true;
61           }
62         }
63       }
64     }
65     return false;
66   }
67
68   @Override
69   public List<String> getChildTerms(String parent, List<String> terms)
70   {
71     List<String> children = new ArrayList<>();
72     for (String term : terms)
73     {
74       if (!term.equals(parent) && isA(term, parent))
75       {
76         children.add(term);
77       }
78     }
79     return children;
80   }
81
82   /**
83    * Answers a (possibly empty) map of any Ontology terms (from the given term
84    * and its parents) which subsume one or more of the target terms. The map key
85    * is an ontology term, and the entry is the list of target terms that are
86    * sub-terms of the key.
87    * <p>
88    * For example if {@code stop_gained} and {@code stop_lost} are known feature
89    * types, then SO term {@ nonsynonymous_variant} is the first common parent of
90    * both terms
91    * 
92    * @param givenTerm
93    *          the term to search from
94    * @param targetTerms
95    *          candidate terms to 'capture' in ontology groupings
96    * @return
97    */
98   @Override
99   public Map<String, List<String>> findSequenceOntologyGroupings(
100           String givenTerm, List<String> targetTerms)
101   {
102     List<String> sortedTypes = new ArrayList<>(targetTerms);
103     Collections.sort(sortedTypes);
104   
105     Map<String, List<String>> parents = new HashMap<>();
106     if (!isValidTerm(givenTerm))
107     {
108       return parents;
109     }
110
111     /*
112      * method: 
113      * walk up featureType and all of its parents
114      * find other feature types which are subsumed by each term
115      * add each distinct aggregation of included feature types to the map
116      */
117     List<String> candidates = new ArrayList<>();
118     SequenceOntologyI so = SequenceOntologyFactory.getInstance();
119
120     candidates.add(givenTerm);
121     while (!candidates.isEmpty())
122     {
123       String term = candidates.remove(0);
124       List<String> includedFeatures = new ArrayList<>();
125       for (String type : sortedTypes)
126       {
127         if (!type.equals(givenTerm) && so.isA(type, term))
128         {
129           includedFeatures.add(type);
130         }
131       }
132       if (!includedFeatures.isEmpty()
133               && !parents.containsValue(includedFeatures))
134       {
135         parents.put(term, includedFeatures);
136       }
137       candidates.addAll(so.getParents(term));
138     }
139   
140     return parents;
141   }
142 }