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.Constraint;
007import org.biopax.paxtools.pattern.MappedConst;
008import org.biopax.paxtools.pattern.Match;
009import org.biopax.paxtools.pattern.util.Blacklist;
010import org.biopax.paxtools.pattern.util.RelType;
011
012import java.util.Arrays;
013import java.util.HashSet;
014
015/**
016 * Some predefined constraints.
017 *
018 * @author Ozgun Babur
019 */
020public class ConBox
021{
022        /**
023         * From EntityReference to the member PhysicalEntity
024         * @return generative constraint to get to the member PhysicalEntity of the EntityReference
025         */
026        public static Constraint erToPE()
027        {
028                return new PathConstraint("EntityReference/entityReferenceOf");
029        }
030
031        /**
032         * From SimplePhysicalEntity to its EntityReference.
033         * @return generative constraint to get the EntityReference of the SimplePhysicalEntity
034         */
035        public static Constraint peToER()
036        {
037                return new PathConstraint("SimplePhysicalEntity/entityReference");
038        }
039
040        /**
041         * From PhysicalEntity to the downstream Control
042         * @return generative constraint to get the Control that the PhysicalEntity is a controller
043         */
044        public static Constraint peToControl()
045        {
046                return new PathConstraint("PhysicalEntity/controllerOf");
047        }
048
049        /**
050         * From PhysicalEntity to the downstream Conversion.
051         * @return generative constraint to get the Conversion that the PhysicalEntity is a controller
052         */
053        public static Constraint peToControlledConv()
054        {
055                return new PathConstraint("PhysicalEntity/controllerOf/controlled*:Conversion");
056        }
057
058        /**
059         * From PhysicalEntity to the downstream Interaction.
060         * @return generative constraint to get the Interaction that the PhysicalEntity is a controller
061         */
062        public static Constraint peToControlledInter()
063        {
064                return new PathConstraint("PhysicalEntity/controllerOf/controlled*:Interaction");
065        }
066
067        /**
068         * From PhysicalEntity to the related Interaction.
069         * @return generative constraint to get the Interaction that the PhysicalEntity is a controller
070         */
071        public static Constraint peToInter()
072        {
073                return new OR(
074                        new MappedConst(peToControlledInter(), 0, 1),
075                        new MappedConst(participatesInInter(), 0, 1));
076        }
077
078        /**
079         * From simple PhysicalEntity to related Conversion. The relation can be through complexes and
080         * generics.
081         *
082         * @param type relationship type
083         * @return generative constraint
084         */
085        public static Constraint simplePEToConv(RelType type)
086        {
087                return new ConstraintChain(linkToComplex(), new ParticipatesInConv(type));
088        }
089
090        /**
091         * From Interaction to the related PhysicalEntity.
092         * @return the constraint
093         */
094        public static Constraint interToPE()
095        {
096                return new OR(
097                        new MappedConst(interToController(), 0, 1),
098                        new MappedConst(participant(), 0, 1));
099        }
100
101        /**
102         * From Control to the controlled Process
103         * @return generative constraint to get the controlled Process of the Control
104         */
105        public static Constraint controlled()
106        {
107                return new PathConstraint("Control/controlled");
108        }
109
110        /**
111         * From Control to the controller PhysicalEntity
112         * @return generative constraint to get the controller PhysicalEntity of the Control
113         */
114        public static Constraint controllerPE()
115        {
116                return new PathConstraint("Control/controller:PhysicalEntity");
117        }
118
119        /**
120         * From Control to the controlled Conversion, traversing downstream Controls recursively.
121         * @return generative constraint to get the downstream (controlled) Conversion of the Control
122         */
123        public static Constraint controlToConv()
124        {
125                return new PathConstraint("Control/controlled*:Conversion");
126        }
127
128        /**
129         * From Control to the controlled TemplateReaction, traversing downstream Controls recursively.
130         * @return generative constraint to get the downstream (controlled) TemplateReaction of the
131         * Control
132         */
133        public static Constraint controlToTempReac()
134        {
135                return new PathConstraint("Control/controlled*:TemplateReaction");
136        }
137
138        /**
139         * From Control to the controlled Interaction, traversing downstream Controls recursively.
140         * @return generative constraint to get the downstream (controlled) Interaction of the Control
141         */
142        public static Constraint controlToInter()
143        {
144                return new PathConstraint("Control/controlled*:Interaction");
145        }
146
147        /**
148         * From Conversion to the upstream Control (and its upstream Control recursively).
149         * @return generative constraint to get the upstream Controls of the Conversion
150         */
151        public static Constraint convToControl()
152        {
153                return new PathConstraint("Conversion/controlledOf*");
154        }
155
156        /**
157         * From Conversion to the controller of the upstream Control (and its upstream Control
158         * recursively).
159         * @return the constraint
160         */
161        public static Constraint convToController()
162        {
163                return new PathConstraint("Conversion/controlledOf*/controller");
164        }
165
166        /**
167         * From Interaction to the upstream Control (and its upstream Control recursively).
168         * @return generative constraint to get the upstream Controls of the Interaction
169         */
170        public static Constraint interToControl()
171        {
172                return new PathConstraint("Interaction/controlledOf*");
173        }
174
175        /**
176         * From PhysicalEntity to the controlled Conversion, skipping the middle Control.
177         * @return generative constraint to get the Conversion that the PhysicalEntity controls
178         */
179        public static Constraint controlsConv()
180        {
181                return new PathConstraint("PhysicalEntity/controllerOf/controlled*:Conversion");
182        }
183
184        /**
185         * From PhysicalEntity to the controlled Interaction, skipping the middle Control.
186         * @return generative constraint to get the Interaction that the PhysicalEntity controls
187         */
188        public static Constraint controlsInteraction()
189        {
190                return new PathConstraint("PhysicalEntity/controllerOf/controlled*:Interaction");
191        }
192
193        /**
194         * Starts from an Interaction and gets next Interactions in temporal order, if ever defined in
195         * a Pathway.
196         * @return generative constraint
197         */
198        public static Constraint nextInteraction()
199        {
200                return new PathConstraint("Interaction/stepProcessOf/nextStep/stepProcess:Interaction");
201        }
202
203        /**
204         * From PhysicalEntity to its generic equivalents, i.e. either parent PhysicalEntity recursively
205         * or member PhysicalEntity recursively. Note that another member of the parent is not a generic
206         * equivalent.
207         * @return generative constraint to get the generic equivalents of the PhysicalEntity
208         */
209        public static Constraint genericEquiv()
210        {
211                return new SelfOrThis(new MultiPathConstraint("PhysicalEntity/memberPhysicalEntity*",
212                        "PhysicalEntity/memberPhysicalEntityOf*"));
213        }
214
215        /**
216         * From Complex to its members recursively (also getting member of the inner complexes).
217         * @return generative constraint to get the members of the Complex
218         */
219        public static Constraint complexMembers()
220        {
221                return new PathConstraint("Complex/component*");
222        }
223
224        /**
225         * From complex to its simple members (members which are of type SimplePhysicalEntity)
226         * recursively.
227         * @return generative constraint to get the simple members of the Complex recursively
228         */
229        public static Constraint simpleMembers()
230        {
231                return new PathConstraint("Complex/component*:SimplePhysicalEntity");
232        }
233
234        /**
235         * From Complex to its members, or the complex itself.
236         * @return generative constraint to get the members of a complex and to itself
237         */
238        public static Constraint withComplexMembers()
239        {
240                return new SelfOrThis(complexMembers());
241        }
242
243        /**
244         * From complex to its simple members recursively, or the Complex itself
245         * @return generative constraint to get the simple members of the Complex recursively, or the
246         * Complex itself
247         */
248        public static Constraint withSimpleMembers()
249        {
250                return new SelfOrThis(simpleMembers());
251        }
252
253        /**
254         * From PhysicalEntity to its parent Complex recursively.
255         * @return generative constraint to get the parent Complex of the PhysicalEntity recursively
256         */
257        public static Constraint complexes()
258        {
259                return new PathConstraint("PhysicalEntity/componentOf*");
260        }
261
262        /**
263         * From PhysicalEntity to parent Complex recursively, or to itself.
264         * @return generative constraint to get the parent Complex of PhysicalEntity recursively, ot to
265         * itself
266         */
267        public static Constraint withComplexes()
268        {
269                return new SelfOrThis(complexes());
270        }
271
272        /**
273         * From Conversion to its left participants.
274         * @return generative constraint to get the left participants of the Conversion
275         */
276        public static Constraint left()
277        {
278                return new PathConstraint("Conversion/left");
279        }
280
281        /**
282         * From Conversion to its right participants.
283         * @return generative constraint to get the right participants of the Conversion
284         */
285        public static Constraint right()
286        {
287                return new PathConstraint("Conversion/right");
288        }
289
290        /**
291         * From PhysicalEntity to the Conversion that it participates.
292         * @return generative constraint to get the Conversions that the PhysicalEntity is a participant
293         * of
294         */
295        public static Constraint participatesInConv()
296        {
297                return new PathConstraint("PhysicalEntity/participantOf:Conversion");
298        }
299
300        /**
301         * From PhysicalEntity to the Interaction that it participates.
302         * @return generative constraint to get the Interactions that the PhysicalEntity is a
303         * participant of
304         */
305        public static Constraint participatesInInter()
306        {
307                return new PathConstraint("PhysicalEntity/participantOf");
308        }
309
310        /**
311         * From Interaction to the controlling Controls recursively, and their controller PEs.
312         * @return the constraint
313         */
314        public static Constraint interToController()
315        {
316                return new PathConstraint("Interaction/controlledOf*:Control/controller:PhysicalEntity");
317        }
318
319        /**
320         * From Complex or SimplePhysicalEntity to the related EntityReference. If Complex, then
321         * EntityReference of simple members (recursively) are related.
322         * @return generative constraint to get the related EntityReference of the Complex or
323         * SimplePhysicalEntity
324         */
325        public static Constraint compToER()
326        {
327                return new PathConstraint("Complex/component*:SimplePhysicalEntity/entityReference");
328        }
329
330        /**
331         * Filters Named to contain a specific name.
332         * @param name name to require
333         * @return constraint to check if the name exists in among names
334         */
335        public static Constraint nameEquals(String name)
336        {
337                return new Field("Named/name", Field.Operation.INTERSECT, name);
338        }
339
340        /**
341         * Filters Named to contain a name from the input set.
342         * @param name name to require
343         * @return constraint
344         */
345        public static Constraint nameEquals(String... name)
346        {
347                return new Field("Named/name", Field.Operation.INTERSECT,
348                        new HashSet<String>(Arrays.asList(name)));
349        }
350
351//      /**
352//       * Filters out ubiquitous elements.
353//       * @param ubiques set of ubique IDs
354//       * @return constraint to filter out ubique based on IDs
355//       */
356//      public static Constraint notUbique(Set<String> ubiques)
357//      {
358//              return new NOT(new IDConstraint(ubiques));
359//      }
360
361        /**
362         * Gets a constraint to ensure that ensures only one of the two PhysicalEntities has an
363         * activity. Size of this constraint is 2.
364         *
365         * @param activating true/false (TODO explain)
366         * @return constraint to make sure only one of the PhysicalEntity has an activity
367         */
368        public static Constraint differentialActivity(boolean activating)
369        {
370                if (activating) return new AND(new MappedConst(new ActivityConstraint(true), 1), new MappedConst(new ActivityConstraint(false), 0));
371                else return new AND(new MappedConst(new ActivityConstraint(true), 0), new MappedConst(new ActivityConstraint(false), 1));
372        }
373
374        /**
375         * From Interaction to its PhysicalEntity participants.
376         * @return generative constraint to get the participants of the Interaction
377         */
378        public static Constraint participant()
379        {
380                return new PathConstraint("Interaction/participant:PhysicalEntity");
381        }
382
383        /**
384         * From Interaction to the related EntityReference of its participants.
385         * @return generative constraint to get the related PhysicalEntity of the participants of an
386         * Interaction
387         */
388        public static Constraint participantER()
389        {
390                return new ConstraintChain(participant(), linkToSpecific(), peToER(), linkedER(false));
391        }
392
393        /**
394         * From TemplateReaction to its products.
395         * @return generative constraint to get the products of the TemplateReaction
396         */
397        public static Constraint product()
398        {
399                return new PathConstraint("TemplateReaction/product");
400        }
401
402        /**
403         * Makes sure the Interaction has no Control
404         * @return constraint to filter out Interactions with a Control
405         */
406        public static Constraint notControlled()
407        {
408                return new Empty(new PathConstraint("Interaction/controlledOf"));
409        }
410
411        /**
412         * Makes sure the EntityReference or the PhysicalEntity belongs to human. Please note that this
413         * check depends on the display name of the related BioSource object to be "Homo sapiens". If
414         * that is not the case, the constraint won't work.
415         * @return constraint to make sure the EntityReference or the PhysicalEntity belongs to human
416         */
417        public static Constraint isHuman()
418        {
419                return new OR(
420                        new MappedConst(new Field("SequenceEntityReference/organism/displayName",
421                                Field.Operation.INTERSECT, "Homo sapiens"), 0),
422                        new MappedConst(new Field("PhysicalEntity/entityReference/organism/displayName",
423                                Field.Operation.INTERSECT, "Homo sapiens"), 0));
424        }
425
426        /**
427         * Makes sure that the object has an Xref with the given ID. This id is not an RDF ID, it is
428         * the value of the Xref, like gene symbol.
429         * @param xrefID xref id
430         * @return constraint
431         */
432        public static Constraint hasXref(String xrefID)
433        {
434                return new Field("XReferrable/xref/id", Field.Operation.INTERSECT, xrefID);
435        }
436
437        /**
438         * Makes sure that the second element (PhysicalEntity) is not a participant of the first element
439         * (Interaction).
440         * @return constraint to make sure that the PhysicalEntity in second index is not a participant
441         * of the Interaction in first index
442         */
443        public static Constraint notAParticipant()
444        {
445                return new NOT(new Field("Interaction/participant", Field.Operation.INTERSECT,
446                        Field.USE_SECOND_ARG));
447        }
448
449        /**
450         * Makes sure that the given physical entity is not related to the entity reference.
451         * @return the constraint
452         * todo: method not tested
453         */
454        public static Constraint peNotRelatedToER()
455        {
456                return new NOT(new ConstraintChain(linkToSpecific(), peToER()));
457        }
458
459        /**
460         * Makes sure the second element (Control) is not a controller to the first element
461         * (Interaction).
462         * @return constraint to filter out cases where the Control at the second index is controlling
463         * the Interaction at the first index.
464         */
465        public static Constraint notControlsThis()
466        {
467                // Asserts the control (first variable), does not control the conversion (second variable)
468                return new NOT(ConBox.controlToInter());
469        }
470
471        /**
472         * Makes sure a PhysicalEntity of any linked member PhysicalEntities toward members are not
473         * labeled as inactive.
474         * @return constraint to filter out PhysicalEntity labeled as inactive.
475         */
476        public static Constraint notLabeledInactive()
477        {
478                // Asserts the PE (and lower equivalent) are not labeled inactive
479                return new NOT(ConBox.modificationConstraint("residue modification, inactive"));
480        }
481
482        /**
483         * Makes sure that the PhysicalEntity or any linked PE contains the modification term. Size = 1.
484         * @param modifTerm term to check
485         * @return constraint to filter out PhysicalEntity not associated to a modification term
486         */
487        public static Constraint modificationConstraint(String modifTerm)
488        {
489                return new FieldOfMultiple(new MappedConst(new LinkedPE(LinkedPE.Type.TO_SPECIFIC), 0),
490                        "PhysicalEntity/feature:ModificationFeature/modificationType/term",
491                        Field.Operation.INTERSECT, modifTerm);
492        }
493
494        /**
495         * Makes a linker constraint from PhysicalEntity to its linked PhysicalEntity towards member
496         * direction.
497         * @return the constraint
498         */
499        public static Constraint linkToSpecific()
500        {
501                return new LinkedPE(LinkedPE.Type.TO_SPECIFIC);
502        }
503
504        /**
505         * Makes a linker constraint from PhysicalEntity to its linked PhysicalEntity towards complex
506         * direction.
507         * @return the constraint
508         */
509        public static Constraint linkToComplex()
510        {
511                return new LinkedPE(LinkedPE.Type.TO_GENERAL);
512        }
513
514        public static Constraint linkedER(boolean up)
515        {
516                return new SelfOrThis(new PathConstraint("EntityReference/memberEntityReference" + (up ? "Of" : "") + "*"));
517        }
518
519        /**
520         * Makes a linker constraint from PhysicalEntity to its linked PhysicalEntity towards member
521         * direction.
522         * @param blacklist used to detect ubiquitous small molecules
523         * @return the constraint
524         */
525        public static Constraint linkToSimple(Blacklist blacklist)
526        {
527                return new LinkedPE(LinkedPE.Type.TO_SPECIFIC, blacklist);
528        }
529
530        /**
531         * Makes a linker constraint from PhysicalEntity to its linked PhysicalEntity towards complex
532         * direction.
533         * @param blacklist used to detect ubiquitous small molecules
534         * @return the constraint
535         */
536        public static Constraint linkToComplex(Blacklist blacklist)
537        {
538                return new LinkedPE(LinkedPE.Type.TO_GENERAL, blacklist);
539        }
540
541        /**
542         * Makes a linker constraint from PhysicalEntity to its linked PhysicalEntity towards complex
543         * direction.
544         *
545         * @param equal true/false (TODO explain)
546         * @return the constraint
547         */
548        public static Constraint equal(boolean equal)
549        {
550                return new Equality(equal);
551        }
552
553        /**
554         * Creates an element type constraint.
555         *
556         * @param clazz a BioPAX type, i.e., corresponding interface class
557         * @return the constraint
558         */
559        public static Constraint type(Class<? extends BioPAXElement> clazz)
560        {
561                return new Type(clazz);
562        }
563
564        /**
565         * Makes sure that the PhysicalEntity do not have member physical entities..
566         * @return the constraint
567         */
568        public static Constraint notGeneric()
569        {
570                return new Empty(new PathConstraint("PhysicalEntity/memberPhysicalEntity"));
571        }
572
573        /**
574         * Makes sure the participant degree (number of Conversions that this is a participant) of the
575         * PhysicalEntity is less than or equal to the parameter.
576         *
577         * @param limit max degree limit
578         * @return the constraint
579         */
580        public static Constraint maxDegree(int limit)
581        {
582                return new Size(new PathConstraint("PhysicalEntity/participantOf:Conversion"), limit,
583                        Size.Type.LESS_OR_EQUAL);
584        }
585
586        public static Constraint source(String dbname)
587        {
588                return new Field("Entity/dataSource/displayName", Field.Operation.INTERSECT, dbname);
589        }
590
591        /**
592         * Makes sure that the two interactions are members of the same pathway.
593         * @return non-generative constraint
594         */
595        public static Constraint inSamePathway()
596        {
597                String s1 = "Interaction/stepProcessOf/pathwayOrderOf";
598                String s2 = "Interaction/pathwayComponentOf";
599                return new OR(new MappedConst(new Field(s1, s1, Field.Operation.INTERSECT), 0, 1),
600                        new MappedConst(new Field(s2, s2, Field.Operation.INTERSECT), 0, 1));
601        }
602
603        /**
604         * Makes sure that the PhysicalEntity is controlling more reactions than it participates
605         * (excluding complex assembly).
606         * @return non-generative constraint
607         */
608        public static Constraint moreControllerThanParticipant()
609        {
610                return new ConstraintAdapter(1)
611                {
612                        PathAccessor partConv = new PathAccessor("PhysicalEntity/participantOf:Conversion");
613                        PathAccessor partCompAss = new PathAccessor("PhysicalEntity/participantOf:ComplexAssembly");
614                        PathAccessor effects = new PathAccessor("PhysicalEntity/controllerOf/controlled*:Conversion");
615
616                        @Override
617                        public boolean satisfies(Match match, int... ind)
618                        {
619                                PhysicalEntity pe = (PhysicalEntity) match.get(ind[0]);
620
621                                int partCnvCnt = partConv.getValueFromBean(pe).size();
622                                int partCACnt = partCompAss.getValueFromBean(pe).size();
623                                int effCnt = effects.getValueFromBean(pe).size();
624
625                                return (partCnvCnt - partCACnt) <= effCnt;
626                        }
627                };
628        }
629
630        /**
631         * Checks if two physical entities have non-empty and different compartments.
632         * @return the constraint
633         */
634        public static Constraint hasDifferentCompartments()
635        {
636                String acStr = "PhysicalEntity/cellularLocation/term";
637                return new Field(acStr, acStr, Field.Operation.NOT_EMPTY_AND_NOT_INTERSECT);
638        }
639
640        /**
641         * Checks if the molecule is a prey of a Y2H experiment.
642         * @return the constraint
643         */
644        public static Constraint isPrey()
645        {
646                return new Field("PhysicalEntity/evidence/experimentalForm/experimentalFormDescription/term",
647                        Field.Operation.INTERSECT, "prey");
648        }
649
650        /**
651         * Checks if the molecule is a bait of a Y2H experiment.
652         * @return the constraint
653         */
654        public static Constraint isBait()
655        {
656                return new Field("PhysicalEntity/evidence/experimentalForm/experimentalFormDescription/term",
657                        Field.Operation.INTERSECT, "bait");
658        }
659}