001package org.biopax.paxtools.util;
002
003import org.biopax.paxtools.model.BioPAXElement;
004
005import java.util.HashSet;
006import java.util.List;
007import java.util.Set;
008
009/**
010 * This class performs set operations based on equivalence.
011 */
012public class SetEquivalenceChecker
013{
014        /**
015         * @param set1 First set to be checked.
016         * @param set2 Second set to be checked
017         * @param <T> Both sets should be of type that extends from T.
018         * @return true iff both sets are of equal size and all objects in set1 has an equivalent object in set2.
019         */
020        public static <T extends BioPAXElement> boolean isEquivalent(Set<? extends T> set1, Set<? extends T> set2)
021        {
022                if (set1 != null && !set1.isEmpty() && set2 != null && !set2.isEmpty())
023                {
024                        int size = set1.size();
025                        if (size == set2.size())
026                        {
027                                EquivalenceGrouper<T> grouper = new EquivalenceGrouper<T>();
028                                grouper.addAll(set1);
029                                if (grouper.getBuckets().size() == size)
030                                {
031                                        grouper.addAll(set2);
032                                        return (grouper.getBuckets().size() == size);
033                                }
034                        }
035                } 
036                
037                //now, only if both null or both empty - return true 
038                if( set1 == null && set2 == null //both null
039                        || // or both not null but empty
040                        set1 != null && set1.isEmpty() && set2 != null && set2.isEmpty()) 
041                { 
042                        return true;
043                }
044                
045                return false;   
046        }
047
048        /**
049         * @param set Set to test if it contains an element equivalent to query
050         * @param query BPE to look for equivalents in set
051         * @return true iff there is an element of set that is equivalent to query.
052         */
053        public static boolean containsEquivalent(Set<? extends BioPAXElement> set, BioPAXElement query)
054        {
055                if (set != null && query != null)
056                {
057                        for (BioPAXElement element2 : set)
058                        {
059                                if (query.isEquivalent(element2))
060                                {
061                                        return true;
062                                }
063                        }
064                }
065                return false;
066        }
067
068        /**
069         * @param set1 First set to be checked.
070         * @param set2 Second set to be checked
071         * @param <T> Both sets should be of type that extends from T.
072         * @return elements of set1 that has an equivalent element in set2
073         */
074        public static <T extends BioPAXElement> Set<T> findEquivalentIntersection(Set<? extends T> set1,
075                        Set<? extends T> set2)
076        {
077
078                Set<T> value = new HashSet<T>();
079
080                if (set1 != null && !set1.isEmpty() && set2 != null && !set2.isEmpty())
081                {
082                        EquivalenceGrouper<T> grouper = new EquivalenceGrouper<T>();
083                        grouper.addAll(set1);
084                        if (grouper.getBuckets().size() < set1.size())
085                        {
086                                throw new IllegalArgumentException("There should not be equivalent elements in a set");
087                        }
088                        grouper.addAll(set2);
089                        for (List<T> ts : grouper.getBuckets())
090                        {
091                                if (ts.size() > 1)
092                                {
093                                        for (T t : ts)
094                                        {
095                                                if (set1.contains(t))
096                                                {
097                                                        value.add(t);
098                                                }
099                                        }
100                                }
101                        }
102                }
103                return value;
104        }
105
106        /**
107         * @param set1 First set to be checked.
108         * @param set2 Second set to be checked
109         * @param <T> Both sets should be of type that extends from T.
110         * @return true iff there are at least one equivalent element between set1 and set2.
111         */
112        public static <T extends BioPAXElement> boolean hasEquivalentIntersection(Set<? extends T> set1,
113                        Set<? extends T> set2)
114        {
115
116                if (set1 != null && !set1.isEmpty() && set2 != null && !set2.isEmpty())
117                {
118                        EquivalenceGrouper<T> grouper = new EquivalenceGrouper<T>();
119                        grouper.addAll(set1);
120                        if (grouper.getBuckets().size() == set1.size())
121                        {
122                                grouper.addAll(set2);
123                                return (grouper.getBuckets().size() < set1.size() + set2.size());
124                        } else
125                        {
126                                throw new IllegalArgumentException("There should not be equivalent elements in a set");
127                        }
128                }
129                return true;
130        }
131
132}