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.PhysicalEntity; 006import org.biopax.paxtools.pattern.Match; 007import org.biopax.paxtools.pattern.util.Blacklist; 008 009import java.util.Collection; 010import java.util.HashSet; 011import java.util.Set; 012 013/** 014 * Many times we want to link PhysicalEntities (PE) while traversing a relation. For instance when 015 * we have a PE and want to go the Interactions that it participates, we may also want to consider 016 * the complexes that the PE is in. Or we also want to traverse homologies (parent or member PEs) 017 * This generative constraint gets related generics (member or parent) and either complexes or 018 * members recursively. 019 * 020 * Linking process is a bit confusing. There two modes: TO_COMPLEX and TO_MEMBER. Linking homologies 021 * is identical for both cases. IT is either parent PEs recursively, or member PEs recursively. But 022 * not parent of a member (recursion do not alternate between parent and member). 023 * 024 * In TO_COMPLEX mode, only parent complexes are linked recursively, and in TO_MEMBER mode, only the 025 * complex member PEs are linked recursively. 026 * 027 * Homology linking and complex-relation linking can alternate recursively. 028 * 029 * @author Ozgun Babur 030 */ 031public class LinkedPE extends ConstraintAdapter 032{ 033 /** 034 * Type of the linking. 035 */ 036 private Type type; 037 038 /** 039 * Accessor to get parent PhysicalEntity. 040 */ 041 private static PathAccessor upperGenAcc = new PathAccessor("PhysicalEntity/memberPhysicalEntityOf*"); 042 043 /** 044 * Accessor to get member PhysicalEntity. 045 */ 046 private static PathAccessor lowerGenAcc = new PathAccessor("PhysicalEntity/memberPhysicalEntity*"); 047 048 /** 049 * Accessor to get parent Complex. 050 */ 051 private static PathAccessor complexAcc = new PathAccessor("PhysicalEntity/componentOf*"); 052 053 /** 054 * Accessor to get complex members. 055 */ 056 private static PathAccessor memberAcc = new PathAccessor("Complex/component*"); 057 058 /** 059 * Constructor with the linking type. 060 * @param type type of desired linking 061 */ 062 public LinkedPE(Type type) 063 { 064 this(type, null); 065 } 066 067 /** 068 * Constructor with the linking type. 069 * @param type type of desired linking 070 * @param blacklist a skip-list of ubiquitous molecules 071 */ 072 public LinkedPE(Type type, Blacklist blacklist) 073 { 074 super(2, blacklist); 075 this.type = type; 076 } 077 078 /** 079 * This is a generative constraint. 080 * @return true 081 */ 082 @Override 083 public boolean canGenerate() 084 { 085 return true; 086 } 087 088 /** 089 * Gets to the linked PhysicalEntity. 090 * @param match current pattern match 091 * @param ind mapped indices 092 * @return linked PhysicalEntity 093 */ 094 @Override 095 public Collection<BioPAXElement> generate(Match match, int... ind) 096 { 097 PhysicalEntity pe = (PhysicalEntity) match.get(ind[0]); 098 Set<BioPAXElement> set = getLinkedElements(pe); 099 100 return set; 101 } 102 103 public Set<BioPAXElement> getLinkedElements(PhysicalEntity pe) 104 { 105 Set<BioPAXElement> set = new HashSet<BioPAXElement>(); 106 set.add(pe); 107 enrichWithGenerics(set, set); 108 return set; 109 } 110 111 /** 112 * Gets the linked homologies and then switches to complex-relationship mode. These two enrich 113 * methods call each other recursively. 114 * @param seed to get the linked elements from 115 * @param all already found links 116 */ 117 protected void enrichWithGenerics(Set<BioPAXElement> seed, Set<BioPAXElement> all) 118 { 119 Set addition; 120 if (type == Type.TO_GENERAL) addition = access(upperGenAcc, seed, all); 121 else addition = access(lowerGenAcc, seed, all); 122 123 all.addAll(addition); 124 seed.addAll(addition); 125 126 enrichWithCM(seed, all); 127 } 128 129 /** 130 * Gets parent complexes or complex members recursively according to the type of the linkage. 131 * @param seed elements to link 132 * @param all already found links 133 */ 134 protected void enrichWithCM(Set<BioPAXElement> seed, Set<BioPAXElement> all) 135 { 136 Set addition = access(type == Type.TO_GENERAL ? complexAcc : memberAcc, seed, all); 137 138 if (blacklist != null) addition = blacklist.getNonUbiqueObjects(addition); 139 140 if (!addition.isEmpty()) 141 { 142 all.addAll(addition); 143 enrichWithGenerics(addition, all); 144 } 145 } 146 147 /** 148 * Uses the given PathAccessor to access fields of the seed and return only new elements that is 149 * not in the given element set (all). 150 * @param pa accessor to the filed 151 * @param seed entities to get their fields 152 * @param all already found values 153 * @return new values 154 */ 155 protected Set access(PathAccessor pa, Set<BioPAXElement> seed, Set<BioPAXElement> all) 156 { 157 Set set = pa.getValueFromBeans(seed); 158 set.removeAll(all); 159 160 // remove blacklisted 161 if (blacklist == null) return set; 162 else return blacklist.getNonUbiqueObjects(set); 163 } 164 165 /** 166 * Two type of linking between PhysicalEntity. 167 */ 168 public enum Type 169 { 170 TO_GENERAL, 171 TO_SPECIFIC 172 } 173}