001package org.biopax.paxtools.io.sif.level3;
002
003import org.apache.commons.logging.Log;
004import org.apache.commons.logging.LogFactory;
005import org.biopax.paxtools.io.sif.BinaryInteractionType;
006import org.biopax.paxtools.model.BioPAXElement;
007import org.biopax.paxtools.model.Model;
008import org.biopax.paxtools.model.level3.*;
009import org.biopax.paxtools.model.level3.Process;
010
011import java.util.*;
012
013import static org.biopax.paxtools.io.sif.BinaryInteractionType.METABOLIC_CATALYSIS;
014import static org.biopax.paxtools.io.sif.BinaryInteractionType.STATE_CHANGE;
015
016/**
017 * A controls a conversion which B is at left or right or both. -
018 * Controls.StateChange (B at both sides (one side may be as a member of a
019 * complex), or B is complex) - Controls.MetabolicChange (B at one side only)
020 * @author Ozgun Babur Date: Dec 29, 2007 Time: 1:27:55 AM
021 */
022public class ControlRule extends InteractionRuleL3Adaptor
023{
024        /**
025         * Log for logging.
026         */
027        private final Log log = LogFactory.getLog(ControlRule.class);
028
029        /**
030         * Supported interaction types.
031         */
032        private static List<BinaryInteractionType> binaryInteractionTypes =
033                        Arrays.asList(METABOLIC_CATALYSIS, STATE_CHANGE);
034
035        /**
036         * Option to mine STATE_CHANGE rule.
037         */
038        private boolean mineStateChange;
039
040        /**
041         * Option to mine METABOLIC_CHANGE rule.
042         */
043        private boolean mineMetabolicChange;
044
045        /**
046         * Map form the source element to the state change data.
047         */
048        private HashMap<BioPAXElement, Set<PEStateChange>> stateChanges = new HashMap<BioPAXElement,
049                        Set<PEStateChange>>();
050
051        /**
052         * Initializes options.
053         * @param options options map
054         */
055        public void initOptionsNotNull(Map options)
056        {
057                mineStateChange = !checkOption(STATE_CHANGE, Boolean.FALSE, options);
058                mineMetabolicChange = !checkOption(METABOLIC_CATALYSIS, Boolean.FALSE, options);
059        }
060
061        /**
062         * When options map is null, then all rules are generated. Otherwise only rules
063         * that are contained in the options map as a key are generated.
064         * @param is3 set to fill in
065         * @param model biopax graph - may be null, has no use here
066         */
067        public void inferInteractionsFromPE(InteractionSetL3 is3, PhysicalEntity pe, Model model)
068        {
069                BioPAXElement source = is3.getGroupMap().getEntityReferenceOrGroup(pe);
070                for (Interaction inter : pe.getParticipantOf())
071                {
072                        if (inter instanceof Control)
073                        {
074                                Control cont = (Control) inter;
075                                // Iterate over all affected conversions of this control
076                                for (Conversion conv : getAffectedConversions(cont, null))
077                                {
078                                        processConversion(is3, source, cont, conv);
079                                }
080                        }
081                }
082        }
083
084        /**
085         * Continue inference with the Control and the Conversion.
086         * @param is3 mined interactions
087         * @param source source of interaction
088         * @param cont the control that source is controller
089         * @param conv the conversion that control is controlling
090         */
091        private void processConversion(InteractionSetL3 is3, BioPAXElement source, Control cont, Conversion conv)
092        {
093                // Collect left and right simple physical entities of conversion in lists
094                Set<BioPAXElement> left = collectEntities(conv.getLeft(), is3);
095                Set<BioPAXElement> right = collectEntities(conv.getRight(), is3);
096                // Detect physical entities which appear on both sides.
097
098                Set<BioPAXElement> intersection = new HashSet<BioPAXElement>(left);
099                intersection.retainAll(right);
100
101                Set<BioPAXElement> union = new HashSet<BioPAXElement>(left);
102                union.addAll(right);
103
104                // Create simple interactions
105                // Try creating a rule for each physical entity in presence list.
106                for (BioPAXElement target : union)
107                {
108                        if (source != target)
109                        {
110                                if (!(target instanceof Group) || !((Group) target).isComplex())
111                                {
112                                        mineTarget(source, target, is3, cont, conv, intersection);
113                                }
114                        }
115                }
116        }
117
118        /**
119         * Create the interaction if the target is changing state.
120         * @param source source of interaction
121         * @param target target of interaction
122         * @param is3 mined rules
123         * @param cont the control that source is controller
124         * @param conv the conversion that control is controlling
125         * @param intersection elements that are both at left and right of the conversion
126         */
127        private void mineTarget(BioPAXElement source, BioPAXElement target, InteractionSetL3 is3, Control cont,
128                        Conversion conv, Set<BioPAXElement> intersection)
129        {
130                if (Simplify.entityHasAChange(target, conv, is3.getGroupMap(), stateChanges.get(target)))
131                {
132
133                        // If it is simple, then we check if it is also on both sides, regarding the
134                        // possibility that it may be nested in a complex.
135                        if (intersection.contains(target))
136                        {
137                                if (mineStateChange)
138                                {
139                                        createAndAdd(source, target, is3, STATE_CHANGE, cont, conv);
140                                }
141                        }
142                        // Else it is a simple molecule appearing on one side of conversion. This means
143                        // it is metabolic change.
144                        else
145                        {
146                                if (mineMetabolicChange)
147                                {
148                                        createAndAdd(source, target, is3, METABOLIC_CATALYSIS, cont, conv);
149                                }
150                        }
151                }
152        }
153
154
155        /**
156         * Creates a list of conversions on which this control has an effect. If the
157         * control controls another control, then it is traversed recursively to find
158         * the affected conversions.
159         * @param cont control
160         * @param convList list of affected conversions
161         * @return list of affected conversions
162         */
163        private List<Conversion> getAffectedConversions(Control cont, List<Conversion> convList)
164        {
165                if (convList == null)
166                {
167                        convList = new ArrayList<Conversion>();
168                }
169                for (Process prcss : cont.getControlled())
170                {
171                        if (prcss instanceof Conversion)
172                        {
173                                convList.add((Conversion) prcss);
174                        } else if (prcss instanceof Control)
175                        {
176                                getAffectedConversions((Control) prcss, convList);
177                        }
178                }
179                return convList;
180        }
181
182        /**
183         * Gets supported interaction types.
184         * @return supported interaction types
185         */
186        public List<BinaryInteractionType> getRuleTypes()
187        {
188                return binaryInteractionTypes;
189        }
190}