001package org.biopax.paxtools.io.sif.level2;
002
003import org.biopax.paxtools.io.sif.BinaryInteractionType;
004import org.biopax.paxtools.io.sif.InteractionSet;
005import org.biopax.paxtools.io.sif.SimpleInteraction;
006import org.biopax.paxtools.model.Model;
007import org.biopax.paxtools.model.level2.*;
008
009import java.util.*;
010
011/**
012 * This is an experimental rule that mines ACTIVATES and INHIBITS relations between molecules.
013 * @author Ozgun Babur
014 */
015public class AffectsRule extends InteractionRuleL2Adaptor
016{
017        /**
018         * Supported interaction types.
019         */
020        private static List<BinaryInteractionType> binaryInteractionTypes =
021                Arrays.asList(BinaryInteractionType.ACTIVATES, BinaryInteractionType .INACTIVATES);
022
023        /**
024         * Infers interactions using the given physicalEntity as seed.
025         * @param interactionSet to be populated
026         * @param pe first physicalEntity
027         * @param model BioPAX model
028         */
029        @Override public void inferInteractionsFromPE(InteractionSet interactionSet, physicalEntity pe,
030                Model model)
031        {
032                for (control cont : pe.getAllInteractions(control.class))
033                {
034                        for (process prcs : cont.getCONTROLLED())
035                        {
036                                if (prcs instanceof conversion)
037                                {
038                                        createInteractions(interactionSet, pe, (conversion) prcs, cont);
039                                }
040                        }
041                }
042        }
043
044        /**
045         * Gets supported interactions types.
046         * @return supported interactions types
047         */
048        public List<BinaryInteractionType> getRuleTypes()
049        {
050                return binaryInteractionTypes;
051        }
052
053        /**
054         * Checks of the participant has an activity.
055         * @param pep participant to check
056         * @return true if there is evidence for activity
057         */
058        private boolean isActive(physicalEntityParticipant pep)
059        {
060                if (affectsSomething(pep) && !isAnnotatedInactive(pep) &&
061                    (!(pep.getPHYSICAL_ENTITY() instanceof complex) || !complexHasInactiveMember(
062                                    (complex) pep.getPHYSICAL_ENTITY())))
063                {
064                        return true;
065                }
066
067                if (isAnnotatedActive(pep))
068                {
069                        return true;
070                }
071
072                if (pep.getPHYSICAL_ENTITY() instanceof
073                        complex && complexHasActiveMember((complex) pep.getPHYSICAL_ENTITY()) &&
074                    !complexHasInactiveMember((complex) pep.getPHYSICAL_ENTITY()))
075                {
076                        return true;
077                }
078
079                return false;
080        }
081
082        /**
083         * Checks of the participant has evidence for inactivity.
084         * @param pep participant to check
085         * @return true if there is evidence for inactivity
086         */
087        private boolean isInactive(physicalEntityParticipant pep)
088        {
089                if (isAnnotatedInactive(pep))
090                {
091                        return true;
092                }
093
094                if (pep.getPHYSICAL_ENTITY() instanceof complex &&
095                        complexHasInactiveMember((complex) pep.getPHYSICAL_ENTITY()) &&
096                        !complexHasActiveMember((complex) pep.getPHYSICAL_ENTITY()))
097                {
098                        return true;
099                }
100
101                return false;
102        }
103
104        /**
105         * Checks if there is an annotation for the participant for its activity.
106         * @param pep participant to check
107         * @return true if there is an annotation for activity
108         */
109        private boolean isAnnotatedActive(physicalEntityParticipant pep)
110        {
111                if (pep instanceof sequenceParticipant)
112                {
113                        for (sequenceFeature sf : ((sequenceParticipant) pep).getSEQUENCE_FEATURE_LIST())
114                        {
115                                if (sf.getFEATURE_TYPE() != null)
116                                {
117                                        for (String term : sf.getFEATURE_TYPE().getTERM())
118                                        {
119                                                if (term.startsWith("active"))
120                                                {
121                                                        return true;
122                                                }
123                                        }
124                                }
125                        }
126                }
127
128                return false;
129        }
130
131        /**
132         * Checks if there is an annotation for the participant for its inactivity.
133         * @param pep participant to check
134         * @return true if there is an annotation for inactivity
135         */
136        private boolean isAnnotatedInactive(physicalEntityParticipant pep)
137        {
138                if (pep instanceof sequenceParticipant)
139                {
140                        for (sequenceFeature sf : ((sequenceParticipant) pep).getSEQUENCE_FEATURE_LIST())
141                        {
142                                if (sf.getFEATURE_TYPE() != null)
143                                {
144                                        for (String term : sf.getFEATURE_TYPE().getTERM())
145                                        {
146                                                if (term.startsWith("inactive") || term.startsWith("ubiquitin"))
147                                                {
148                                                        return true;
149                                                }
150                                        }
151                                }
152                        }
153                }
154
155                return false;
156        }
157
158        /**
159         * Checks if this participant or the the ones in equivalent state are effecting something.
160         * @param pep participant to check
161         * @return true if this one or an equivalent affects something
162         */
163        private boolean affectsSomething(physicalEntityParticipant pep)
164        {
165                physicalEntity pe = pep.getPHYSICAL_ENTITY();
166
167                for (physicalEntityParticipant par : pe.isPHYSICAL_ENTITYof())
168                {
169                        if (par != pep && par.isInEquivalentState(pep))
170                        {
171                                for (interaction inter : par.isPARTICIPANTSof())
172                                {
173                                        if (inter instanceof control)
174                                        {
175                                                return true;
176                                        }
177                                }
178                        }
179                }
180
181                return false;
182        }
183
184        /**
185         * Checks if the complex has an active member.
186         * @param cmp complex to check
187         * @return true if complex has an active member
188         */
189        private boolean complexHasActiveMember(complex cmp)
190        {
191                for (physicalEntityParticipant pep : cmp.getCOMPONENTS())
192                {
193                        if (isAnnotatedActive(pep))
194                        {
195                                return true;
196                        } else if (pep.getPHYSICAL_ENTITY() instanceof complex && complexHasActiveMember(
197                                        (complex) pep.getPHYSICAL_ENTITY()))
198                        {
199                                return true;
200                        }
201                }
202                return false;
203        }
204
205        /**
206         * Checks if the complex has an inactive member.
207         * @param cmp complex to check
208         * @return true if complex has an inactive member
209         */
210        private boolean complexHasInactiveMember(complex cmp)
211        {
212                for (physicalEntityParticipant pep : cmp.getCOMPONENTS())
213                {
214                        if (isAnnotatedInactive(pep))
215                        {
216                                return true;
217                        } else if (pep.getPHYSICAL_ENTITY() instanceof complex && complexHasInactiveMember(
218                                        (complex) pep.getPHYSICAL_ENTITY()))
219                        {
220                                return true;
221                        }
222                }
223                return false;
224        }
225
226        /**
227         * Gets active or inactive members of a complex.
228         * @param cmp complex to get members
229         * @param active desired activity state
230         * @param set set to collect to, initialized if null
231         * @return same set
232         */
233        private Set<physicalEntity> getMembers(complex cmp, boolean active, Set<physicalEntity> set)
234        {
235                if (set == null) set = new HashSet<physicalEntity>();
236
237                for (physicalEntityParticipant pep : cmp.getCOMPONENTS())
238                {
239                        if (!(pep.getPHYSICAL_ENTITY() instanceof complex) &&
240                                ((active && isAnnotatedActive(pep)) || (!active && isAnnotatedInactive(pep))))
241                        {
242                                set.add(pep.getPHYSICAL_ENTITY());
243                        } else if (pep.getPHYSICAL_ENTITY() instanceof complex)
244                        {
245                                getMembers((complex) pep.getPHYSICAL_ENTITY(), active, set);
246                        }
247                }
248                return set;
249        }
250
251        /**
252         * Gets members of the complex recursively.
253         * @param cmp complex to get members
254         * @param set set to collect to
255         * @return members
256         */
257        private Set<physicalEntityParticipant> getMembers(complex cmp,
258                Set<physicalEntityParticipant> set)
259        {
260                if (set == null) set = new HashSet<physicalEntityParticipant>();
261
262                for (physicalEntityParticipant pep : cmp.getCOMPONENTS())
263                {
264                        if (pep.getPHYSICAL_ENTITY() instanceof complex)
265                        {
266                                getMembers((complex) pep.getPHYSICAL_ENTITY(), set);
267                        } else
268                        {
269                                set.add(pep);
270                        }
271                }
272                return set;
273        }
274
275        /**
276         * Creates the inferred interaction.
277         * @param interactionSet set to add new interactions
278         * @param A seed of the interaction
279         * @param conv conversion that affects B
280         * @param cont control where A is controller
281         */
282        private void createInteractions(InteractionSet  interactionSet, physicalEntity A,
283                conversion conv, control cont)
284        {
285                boolean l2r = true;
286
287                if (cont instanceof catalysis)
288                {
289                        Direction dir = ((catalysis) cont).getDIRECTION();
290
291                        if (dir != null)
292                        {
293                                if (dir == Direction.REVERSIBLE) return;
294
295                                if (dir == Direction.IRREVERSIBLE_RIGHT_TO_LEFT ||
296                                        dir == Direction.PHYSIOL_RIGHT_TO_LEFT)
297                                {
298                                        l2r = false;
299                                }
300                        }
301                }
302
303                int effect = 1;
304                if (cont != null && cont.getCONTROL_TYPE() != null)
305                {
306                        effect = cont.getCONTROL_TYPE().toString().startsWith("ACT") ? 1 : -1;
307                }
308
309                Set<physicalEntityParticipant> input = l2r ? conv.getLEFT() : conv.getRIGHT();
310                Set<physicalEntityParticipant> output = !l2r ? conv.getLEFT() : conv.getRIGHT();
311
312                enrichWithMembers(input);
313                enrichWithMembers(output);
314
315                Set<physicalEntityParticipant[]> matching = getEntityMatching(input, output);
316
317                for (physicalEntityParticipant[] tuple : matching)
318                {
319                        int inp = isActive(tuple[0]) ? 1 : isInactive(tuple[0]) ? -1 : 0;
320                        int oup = isActive(tuple[1]) ? 1 : isInactive(tuple[1]) ? -1 : 0;
321
322                        if (oup != 0 && inp != oup)
323                        {
324                                int sign = oup * effect;
325
326                                assert sign != 0;
327
328                                if (sign == 1)
329                                {
330                                        interactionSet.add(new SimpleInteraction(
331                                                A, tuple[1].getPHYSICAL_ENTITY(), BinaryInteractionType.ACTIVATES));
332                                } else
333                                {
334                                        assert sign == -1;
335
336                                        interactionSet.add(new SimpleInteraction(
337                                                A, tuple[1].getPHYSICAL_ENTITY(), BinaryInteractionType.INACTIVATES));
338                                }
339                        }
340                }
341
342                for (physicalEntityParticipant pep : output)
343                {
344                        if (pep.getPHYSICAL_ENTITY() instanceof complex)
345                        {
346                                int eff = isActive(pep) ? 1 : isInactive(pep) ? -1 : 0;
347                                int sign = eff * effect;
348
349                                if (sign == 1)
350                                {
351                                        interactionSet.add(new SimpleInteraction(
352                                                A, pep.getPHYSICAL_ENTITY(), BinaryInteractionType.ACTIVATES));
353                                }
354                                else if (sign == -1)
355                                {
356                                        interactionSet.add(new SimpleInteraction(
357                                                A, pep.getPHYSICAL_ENTITY(), BinaryInteractionType.INACTIVATES));
358                                }
359
360                                if (sign != 0)
361                                {
362                                        for (physicalEntity pe :
363                                                eff == 1 ? getMembers((complex) pep.getPHYSICAL_ENTITY(), true, null) :
364                                                        getMembers((complex) pep.getPHYSICAL_ENTITY(), false, null))
365                                        {
366                                                interactionSet.add(new SimpleInteraction(
367                                                        pe, pep.getPHYSICAL_ENTITY(), BinaryInteractionType.ACTIVATES));
368                                        }
369                                }
370                        }
371                }
372        }
373
374        /**
375         * Enriches the given set with members of the complexes in the set.
376         * @param set set to enrich
377         */
378        private void enrichWithMembers(Set<physicalEntityParticipant> set)
379        {
380                for (physicalEntityParticipant pep : new HashSet<physicalEntityParticipant>(set))
381                {
382                        if (pep.getPHYSICAL_ENTITY() instanceof complex)
383                        {
384                                set.addAll(getMembers((complex) pep.getPHYSICAL_ENTITY(), null));
385                        }
386                }
387        }
388
389        /**
390         * Gets the pairs of participants in two sets, where their physicalEntity is the same.
391         * @param set1 first set
392         * @param set2 second set
393         * @return pairs of participants
394         */
395        private Set<physicalEntityParticipant[]> getEntityMatching(Set<physicalEntityParticipant> set1,
396                Set<physicalEntityParticipant> set2)
397        {
398                Set<physicalEntityParticipant[]> tuples = new HashSet<physicalEntityParticipant[]>();
399
400                for (physicalEntityParticipant pep1 : set1)
401                {
402                        for (physicalEntityParticipant pep2 : set2)
403                        {
404                                if (pep1.getPHYSICAL_ENTITY() == pep2.getPHYSICAL_ENTITY())
405                                {
406                                        tuples.add(new physicalEntityParticipant[]{pep1, pep2});
407                                }
408                        }
409                }
410                return tuples;
411        }
412}