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.*;
006import org.biopax.paxtools.pattern.Match;
007
008import java.util.Collection;
009import java.util.HashSet;
010import java.util.Set;
011
012/**
013 * This constraint is used to collect related EntityReference of the participant physical entities.
014 * The constraint let's users to set some participants as taboo, and they are excluded from
015 * analysis.
016 *
017 * Var0 - Interaction
018 * Var1 - Taboo element number 1
019 * ...
020 * Var(numTabooElements+1) - Last taboo element
021 * Var(numTabooElements+2) - The related EntityReference
022 *
023 * @author Ozgun Babur
024 */
025public class InterToPartER extends ConstraintAdapter
026{
027        /**
028         * Direction to go. When this parameter is used, the interaction has to be a Conversion.
029         */
030        private Direction direction;
031
032        /**
033         * Constraint used for traversing towards simpler PE.
034         */
035        private static final LinkedPE linker = new LinkedPE(LinkedPE.Type.TO_SPECIFIC);
036
037        /**
038         * Accessor from PE to ER.
039         */
040        private static final PathAccessor pe2ER =
041                new PathAccessor("SimplePhysicalEntity/entityReference");
042
043        /**
044         * Constructor with parameters. A taboo element is the participant that we want to exclude from
045         * the analysis. User should provide the number of taboo elements, then during execution, these
046         * elements will be fetched from the current match.
047         *
048         * @param numOfTabooElements the number of entities to exclude from the analysis
049         */
050        public InterToPartER(int numOfTabooElements)
051        {
052                super(numOfTabooElements + 2);
053        }
054
055        /**
056         * Constructor with parameters. A taboo element is the participant that we want to exclude from
057         * the analysis. User should provide the number of taboo elements, then during execution, these
058         * elements will be fetched from the current match. The direction is left, or right, or both
059         * sides of the Conversion.
060         *
061         * @param direction ide(s) of an interaction to consider
062         * @param numOfTabooElements the number of entities to exclude from the analysis
063         */
064        public InterToPartER(Direction direction, int numOfTabooElements)
065        {
066                this(numOfTabooElements);
067                this.direction = direction;
068        }
069
070        /**
071         * Constructor without parameters. There are no taboo elements.
072         */
073        public InterToPartER()
074        {
075                this(0);
076        }
077
078        /**
079         * Constructor with direction. There are no taboo elements.
080         *
081         * @param direction - side(s) of an interaction to consider;
082         *                    see {@link org.biopax.paxtools.pattern.constraint.InterToPartER.Direction}
083         */
084        public InterToPartER(Direction direction)
085        {
086                this();
087                this.direction = direction;
088        }
089
090        /**
091         * This is a generative constraint.
092         * @return true if the constraint can generate candidates
093         */
094        @Override
095        public boolean canGenerate()
096        {
097                return true;
098        }
099
100        /**
101         * Iterated over non-taboo participants and collectes related ER.
102         * @param match current pattern match
103         * @param ind mapped indices
104         * @return related participants
105         */
106        @Override
107        public Collection<BioPAXElement> generate(Match match, int... ind)
108        {
109                Interaction inter = (Interaction) match.get(ind[0]);
110
111                Set<Entity> taboo = new HashSet<Entity>();
112
113                for (int i = 1; i < getVariableSize() - 1; i++)
114                {
115                        taboo.add((Entity) match.get(ind[i]));
116                }
117
118                if (direction == null) return generate(inter, taboo);
119                else return generate((Conversion) inter, direction, taboo);
120        }
121
122        /**
123         * Gets the related entity references of the given interaction.
124         * @param inter interaction
125         * @param taboo entities to ignore/skip
126         * @return entity references
127         */
128        protected Collection<BioPAXElement> generate(Interaction inter, Set<Entity> taboo)
129        {
130                Set<BioPAXElement> simples = new HashSet<BioPAXElement>();
131
132                for (Entity part : inter.getParticipant())
133                {
134                        if (part instanceof PhysicalEntity && !taboo.contains(part))
135                        {
136                                simples.addAll(linker.getLinkedElements((PhysicalEntity) part));
137                        }
138                }
139
140                return pe2ER.getValueFromBeans(simples);
141        }
142
143        /**
144         * Gets the related entity references of the given interaction,
145         * @param conv conversion interaction
146         * @param direction which side(s) participants of the conversion to consider
147         * @param taboo skip list of entities
148         * @return entity references
149         */
150        protected Collection<BioPAXElement> generate(Conversion conv, Direction direction,
151                Set<Entity> taboo)
152        {
153                if (direction == null) throw new IllegalArgumentException("Direction cannot be null");
154
155                if (!(direction == Direction.BOTHSIDERS || direction == Direction.ONESIDERS))
156                {
157                        Set<BioPAXElement> simples = new HashSet<BioPAXElement>();
158
159                        for (Entity part : direction == Direction.ANY ? conv.getParticipant() :
160                                direction == Direction.LEFT ? conv.getLeft() : conv.getRight())
161                        {
162                                if (part instanceof PhysicalEntity && !taboo.contains(part))
163                                {
164                                        simples.addAll(linker.getLinkedElements((PhysicalEntity) part));
165                                }
166                        }
167
168                        return pe2ER.getValueFromBeans(simples);
169                }
170                else
171                {
172                        Set<BioPAXElement> leftSimples = new HashSet<BioPAXElement>();
173                        Set<BioPAXElement> rightSimples = new HashSet<BioPAXElement>();
174
175                        for (PhysicalEntity pe : conv.getLeft())
176                        {
177                                if (!taboo.contains(pe)) leftSimples.addAll(linker.getLinkedElements(pe));
178                        }
179                        for (PhysicalEntity pe : conv.getRight())
180                        {
181                                if (!taboo.contains(pe)) rightSimples.addAll(linker.getLinkedElements(pe));
182                        }
183
184                        Set leftERs = pe2ER.getValueFromBeans(leftSimples);
185                        Set rightERs = pe2ER.getValueFromBeans(rightSimples);
186
187                        if (direction == Direction.ONESIDERS)
188                        {
189                                // get all but intersection
190                                Set temp = new HashSet(leftERs);
191                                leftERs.removeAll(rightERs);
192                                rightERs.removeAll(temp);
193                                leftERs.addAll(rightERs);
194                        }
195                        else // BOTHSIDERS
196                        {
197                                // get intersection
198                                leftERs.retainAll(rightERs);
199                        }
200
201                        return leftERs;
202                }
203        }
204
205        public enum Direction
206        {
207                LEFT,
208                RIGHT,
209                ANY,
210                ONESIDERS,
211                BOTHSIDERS
212        }
213}