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