001package org.biopax.paxtools.io.sif.level2;
002
003import org.apache.commons.logging.Log;
004import org.apache.commons.logging.LogFactory;
005import org.biopax.paxtools.io.sif.BinaryInteractionType;
006import org.biopax.paxtools.io.sif.InteractionSet;
007import org.biopax.paxtools.io.sif.MaximumInteractionThresholdExceedException;
008import org.biopax.paxtools.io.sif.SimpleInteraction;
009import org.biopax.paxtools.model.Model;
010import org.biopax.paxtools.model.level2.complex;
011import org.biopax.paxtools.model.level2.physicalEntity;
012import org.biopax.paxtools.model.level2.physicalEntityParticipant;
013
014import java.util.Arrays;
015import java.util.List;
016import java.util.Map;
017import java.util.Set;
018
019import static org.biopax.paxtools.io.sif.BinaryInteractionType.COMPONENT_OF;
020import static org.biopax.paxtools.io.sif.BinaryInteractionType.IN_SAME_COMPONENT;
021
022/**
023 * Component.InSame: A and B are components of same flattened complex structure,
024 * A and B are simple. Component.Of: A is component of B, B is complex, A may be
025 * nested multiple levels in B.
026 * @author Ozgun Babur
027 */
028public class ComponentRule extends InteractionRuleL2Adaptor
029{
030        /**
031         * Supported interaction types.
032         */
033        private static List<BinaryInteractionType> binaryInteractionTypes =
034                Arrays.asList(COMPONENT_OF, IN_SAME_COMPONENT);
035
036        /**
037         * Maximum number of members of a complex to process.
038         */
039        private long threshold;
040
041        /**
042         * Log for logging.
043         */
044        private static Log log = LogFactory.getLog(ComponentRule.class);
045
046        /**
047         * Option to just skip large complexes without throwing an exception.
048         */
049        boolean suppressExceptions;
050
051        /**
052         * Option to mine COMPONENT_OF type.
053         */
054        private boolean componentOf;
055
056        /**
057         * Option to mine IN_SAME_COMPONENT type.
058         */
059        private boolean inSameComponent;
060
061        /**
062         * Constructor with default values.
063         */
064        public ComponentRule()
065        {
066                this(Integer.MAX_VALUE, false);
067        }
068
069        /**
070         * Constructor with threshold
071         * @param threshold limit for the member size of the complex to mine
072         */
073        public ComponentRule(int threshold)
074        {
075                this(threshold, false);
076        }
077
078        /**
079         * Constructor with threshold and exception suppressing option.
080         * @param threshold limit for the member size of the complex to mine
081         * @param suppressExceptions if true, does not throw exception for large complexes, just skips
082         * them
083         */
084        public ComponentRule(int threshold, boolean suppressExceptions)
085        {
086                this.threshold = threshold;
087                this.suppressExceptions = suppressExceptions;
088        }
089
090        /**
091         * Infer starting from the given physicalEntity.
092         * @param interactionSet to be populated
093         * @param A source of the interaction
094         * @param model BioPAX model
095         */
096        @Override public void inferInteractionsFromPE(InteractionSet interactionSet, physicalEntity A, Model model)
097        {
098                if (!(A instanceof complex))
099                {
100
101                        // Iterate all PEPs of A and process that goes into a complex
102
103                        for (physicalEntityParticipant pep : A.isPHYSICAL_ENTITYof())
104                        {
105                                if (pep.isCOMPONENTof() != null)
106                                {
107                                        complex comp = pep.isCOMPONENTof();
108
109                                        processComplex(interactionSet, A, comp);
110                                }
111                        }
112                }
113        }
114
115        /**
116         * This method is called for each complex that A is in, regardless of the level
117         * of nesting. If it is also detected that this complex is the most outer
118         * complex, then another recursive search is initiated for mining
119         * Component.InSame rule.
120         * @param interactionSet interaction repository
121         * @param A first physical entity
122         * @param comp complex being processed
123         */
124        private void processComplex(InteractionSet interactionSet, physicalEntity A, complex comp)
125        {
126
127                if (componentOf)
128                {
129                        // Add Component.Of rule
130                        SimpleInteraction si = new SimpleInteraction(A, comp, COMPONENT_OF);
131                        si.addMediator(comp);
132                        interactionSet.add(si);
133                }
134
135                // Flag for detecting if this complex is most outer one.
136                boolean mostOuter = true;
137
138                // Iterate all PEPs of complex and process that goes into a complex
139
140                for (physicalEntityParticipant pep : comp.isPHYSICAL_ENTITYof())
141                {
142                        if (pep.isCOMPONENTof() != null)
143                        {
144                                complex outer = pep.isCOMPONENTof();
145                                mostOuter = false;
146                                processComplex(interactionSet, A, outer);
147                        }
148                }
149
150                // Search towards other members only if this is the most outer complex
151                // and if options let for sure
152
153
154                if (mostOuter && inSameComponent)
155                {
156                        // Iterate other members for components_of_same_complex rule
157                        processComplexMembers(interactionSet, A, comp, 0);
158                }
159        }
160
161        /**
162         * Recursive method for mining rule Component.InSame. We search towards
163         * children only because we make sure that we start form the most outer
164         * complex.
165         * @param interactionSet repository of rules
166         * @param pe A
167         * @param comp common complex
168         * @param size threshold control
169         */
170        private void processComplexMembers(InteractionSet interactionSet, physicalEntity pe, complex comp, int size)
171        {
172
173
174                Set<physicalEntityParticipant> components = comp.getCOMPONENTS();
175                if ((size += components.size()) > threshold)
176                {
177                        log.warn("This complex is too large. Skipping");
178                        if (suppressExceptions) return;
179                        else throw new MaximumInteractionThresholdExceedException(pe.toString());
180                }
181                for (physicalEntityParticipant pep : components)
182                {
183                        physicalEntity member = pep.getPHYSICAL_ENTITY();
184
185                        if (pe != member)
186                        {
187                                if (member instanceof complex)
188                                {
189                                        // recursive call for inner complex
190                                        processComplexMembers(interactionSet, pe, (complex) member, size);
191                                } else
192                                {
193                                        // rule generation for simple member
194                                        SimpleInteraction si = new SimpleInteraction(pe, member, IN_SAME_COMPONENT);
195                                        si.addMediator(comp);
196                                        interactionSet.add(si);
197                                }
198                        }
199                }
200        }
201
202        /**
203         * Gets supported interaction types.
204         * @return supported interaction types
205         */
206        public List<BinaryInteractionType> getRuleTypes()
207        {
208                return binaryInteractionTypes;
209        }
210
211        /**
212         * Initializes options.
213         * @param options options map
214         */
215        @Override public void initOptionsNotNull(Map options)
216        {
217                componentOf = !options.containsKey(COMPONENT_OF) || options.get(COMPONENT_OF).equals(Boolean.TRUE);
218                inSameComponent =
219                                !options.containsKey(IN_SAME_COMPONENT) || options.get(IN_SAME_COMPONENT).equals(Boolean.TRUE);
220
221        }
222}
223