001package org.biopax.paxtools.pattern.constraint;
002
003import org.biopax.paxtools.controller.PathAccessor;
004import org.biopax.paxtools.model.BioPAXElement;
005import org.biopax.paxtools.model.level3.EntityReference;
006import org.biopax.paxtools.model.level3.ModificationFeature;
007import org.biopax.paxtools.model.level3.SimplePhysicalEntity;
008import org.biopax.paxtools.pattern.Match;
009
010import java.util.HashMap;
011import java.util.HashSet;
012import java.util.Map;
013import java.util.Set;
014
015/**
016 * This is a very specialized constraint that checks if two PhysicalEntity of the same
017 * EntityReference have differential features, such that we can predict an activity change based on
018 * gain or loss of these features. To use this constraint, user should be able to supply maps that
019 * categorize features as activating or inhibiting.
020 *
021 * @author Ozgun Babur
022 */
023public class ActivityModificationChangeConstraint extends ConstraintAdapter
024{
025        /**
026         * Desired change.
027         */
028        boolean activating;
029
030        /**
031         * Accessor to modification features.
032         */
033        static PathAccessor pa = new PathAccessor("PhysicalEntity/feature:ModificationFeature");
034
035        /**
036         * Some general modification sub-strings to use if exact terms are not conclusive.
037         */
038        protected final static String[] general = new String[]{
039                "phospho", "ubiqutin", "acetyl", "myristoyl", "palmitoyl", "glucosyl"};
040
041        /**
042         * Map from EntityReference to the activity related features.
043         */
044        Map<EntityReference, Set<ModificationFeature>> activityFeat;
045
046        /**
047         * Map from EntityReference to the inactivity related features.
048         */
049        Map<EntityReference, Set<ModificationFeature>> inactivityFeat;
050
051        /**
052         * Map from EntityReference to the activity related terms.
053         */
054        Map<EntityReference, Set<String>> activityStr;
055
056        /**
057         * Map from EntityReference to the inactivity related terms.
058         */
059        Map<EntityReference, Set<String>> inactivityStr;
060
061        /**
062         * Constructor with the desired change and maps to activating and inactivating features,
063         * @param activating desired change
064         * @param activityFeat map from EntityReference to the activating features
065         * @param inactivityFeat map from EntityReference to the inactivating features
066         */
067        public ActivityModificationChangeConstraint(boolean activating,
068                Map<EntityReference, Set<ModificationFeature>> activityFeat,
069                Map<EntityReference, Set<ModificationFeature>> inactivityFeat)
070        {
071                super(2);
072                this.activating = activating;
073                this.activityFeat = activityFeat;
074                this.inactivityFeat = inactivityFeat;
075
076                activityStr = extractModifNames(activityFeat);
077                inactivityStr = extractModifNames(inactivityFeat);
078        }
079
080        /**
081         * Checks the gained and and lost features to predict the activity change is the desired change.
082         * If exact matching (terms with locations) is not conclusive, then terms without locations are
083         * checked. If still not conclusive, then approximate matching is used.
084         * @param match current pattern match
085         * @param ind mapped indices
086         * @return true if the modification gain or loss is mapped to the desired change
087         */
088        @Override
089        public boolean satisfies(Match match, int... ind)
090        {
091                BioPAXElement ele1 = match.get(ind[0]);
092                BioPAXElement ele2 = match.get(ind[1]);
093
094                EntityReference er = ((SimplePhysicalEntity) ele1).getEntityReference();
095
096                Set set1 = pa.getValueFromBean(ele1);
097                Set set2 = pa.getValueFromBean(ele2);
098
099                Set gain = new HashSet(set2);
100                gain.removeAll(set1);
101
102                Set loss = new HashSet(set1);
103                loss.removeAll(set2);
104
105                int activatingCnt = 0;
106                int inhibitingCnt = 0;
107
108                for (Object o : gain)
109                {
110                        if (activityFeat.get(er).contains(o)) activatingCnt++;
111                        if (inactivityFeat.get(er).contains(o)) inhibitingCnt++;
112                }
113                for (Object o : loss)
114                {
115                        if (inactivityFeat.get(er).contains(o)) activatingCnt++;
116                        if (activityFeat.get(er).contains(o)) inhibitingCnt++;
117                }
118
119                // Match without considering the locations
120
121                Set<String> gainTypes = null;
122                Set<String> lossTypes = null;
123
124                if (activatingCnt + inhibitingCnt == 0)
125                {
126                        gainTypes = extractModifNames(gain);
127                        lossTypes = extractModifNames(loss);
128
129                        for (String s : gainTypes)
130                        {
131                                if (activityStr.get(er).contains(s)) activatingCnt++;
132                                if (inactivityStr.get(er).contains(s)) inhibitingCnt++;
133                        }
134                        for (String s : lossTypes)
135                        {
136                                if (inactivityStr.get(er).contains(s)) activatingCnt++;
137                                if (activityStr.get(er).contains(s)) inhibitingCnt++;
138                        }
139                }
140
141                // Try to match modifications with approximate name matching
142
143                if (activatingCnt + inhibitingCnt == 0)
144                {
145                        for (String genName : general)
146                        {
147                                boolean foundInActivating = setContainsGeneralTerm(activityStr.get(er), genName);
148                                boolean foundInInhibiting = setContainsGeneralTerm(inactivityStr.get(er), genName);
149
150                                if (foundInActivating == foundInInhibiting) continue;
151
152                                boolean foundInGain = setContainsGeneralTerm(gainTypes, genName);
153                                boolean foundInLose = setContainsGeneralTerm(lossTypes, genName);
154
155                                if (foundInGain == foundInLose) continue;
156
157                                if (foundInActivating && foundInGain) activatingCnt++;
158                                else if (foundInInhibiting && foundInLose) activatingCnt++;
159                                else if (foundInActivating && foundInLose) inhibitingCnt++;
160                                else /*if (foundInInhibiting && foundInGain)*/ inhibitingCnt++;
161                        }
162                }
163
164                if (activatingCnt > 0 && inhibitingCnt > 0) return false;
165                return activating ? activatingCnt > 0 : inhibitingCnt > 0;
166        }
167
168
169        /**
170         * Extracts the modification terms from the moficiation features.
171         * @param mfMap map for the features
172         * @return map from EntityReference to the set of the extracted terms
173         */
174        protected Map<EntityReference, Set<String>> extractModifNames(Map mfMap)
175        {
176                Map<EntityReference, Set<String>> map = new HashMap<EntityReference, Set<String>>();
177
178                for (Object o : mfMap.keySet())
179                {
180                        EntityReference er = (EntityReference) o;
181                        map.put(er, extractModifNames((Set) mfMap.get(er)));
182                }
183
184                return map;
185        }
186
187        /**
188         * Extracts terms of the modification features.
189         * @param mfSet set of modification features
190         * @return set of extracted terms
191         */
192        protected Set<String> extractModifNames(Set mfSet)
193        {
194                Set<String> set = new HashSet<String>();
195
196                for (Object o : mfSet)
197                {
198                        ModificationFeature mf = (ModificationFeature) o;
199                        if (mf.getModificationType() != null && !mf.getModificationType().getTerm().isEmpty())
200                        {
201                                set.add(mf.getModificationType().getTerm().iterator().next());
202                        }
203                }
204                return set;
205        }
206
207        /**
208         * Checks if any element in the set contains the term.
209         * @param set set to check
210         * @param term term to search for
211         * @return true if any element contains the term
212         */
213        protected boolean setContainsGeneralTerm(Set<String> set, String term)
214        {
215                for (String s : set)
216                {
217                        if (s.contains(term)) return true;
218                }
219                return false;
220        }
221}