    001package com.hammurapi.extract;
    002
    003import java.util.Arrays;
    004import java.util.Set;
    005
    006/**
    007 * Result of comparison of two extractors/predicates.
    008 * @author Pavel Vlasov
    009 *
    010 */
    011public class ComparisonResult {
    012
    013        // Not mapping constants
    014        public static final ComparisonResult EQUAL_NM =  new ComparisonResult(Type.EQUAL, null);
    015        public static final ComparisonResult UNEQUAL_NM =  new ComparisonResult(Type.UNEQUAL, null);
    016        public static final ComparisonResult LESS_RESTRICTIVE_NM =  new ComparisonResult(Type.LESS_RESTRICTIVE, null);
    017        public static final ComparisonResult MORE_RESTRICTIVE_NM =  new ComparisonResult(Type.MORE_RESTRICTIVE, null);
    018        public static final ComparisonResult NOT_EQUAL_NM =  new ComparisonResult(Type.NOT_EQUAL, null);
    019        public static final ComparisonResult OPPOSITE_NM =  new ComparisonResult(Type.OPPOSITE, null);
    020        public static final ComparisonResult OPPOSITE_LESS_RESTRICTIVE_NM =  new ComparisonResult(Type.OPPOSITE_LESS_RESTRICTIVE, null);
    021        public static final ComparisonResult OPPOSITE_MORE_RESTRICTIVE_NM =  new ComparisonResult(Type.OPPOSITE_MORE_RESTRICTIVE, null);
    022
    023        /**
    024         * Result of extractor comparison.
    025         * @author Pavel Vlasov.
    026         *
    027         */
    028        public enum Type {
    029                /**
    030                 * Extractors are equal.
    031                 */
    032                EQUAL,
    033                /**
    034                 * Extractors are not equal, i.e. no conclusion can be drawn about values
    035                 * returned by extractors.
    036                 */
    037                NOT_EQUAL,
    038
    039                // Enums below are applicable only to predicates.
    040                /**
    041                 * This predicate is less restrictive than the parameter
    042                 * predicate. E.g. x&lt;=5 is less restrictive than x&lt;5.
    043                 */
    044                LESS_RESTRICTIVE,
    045                /**
    046                 * This predicate is more restrictive than the parameter
    047                 * predicate. E.g. x&lt;6 is more restrictive than x&lt;7.
    048                 */
    049                MORE_RESTRICTIVE,
    050                /**
    051                 * When this predicate evaluates to true, the parameter
    052                 * predicate evaluates to false and vice-versa.
    053                 */
    054                OPPOSITE,
    055                /**
    056                 * The opposite of this predicate is less restrictive than
    057                 * the parameter predicate.
    058                 * E.g. x&gt;5 opposite is x&lt;=5 and it is is less restrictive than x&lt;5.
    059                 */
    060                OPPOSITE_LESS_RESTRICTIVE,
    061                /**
    062                 * The opposite of this predicate is more restrictive than
    063                 * the parameter predicate.
    064                 * E.g. x&gt;5 opposite is x&lt;=5 and it is is more restrictive than x&lt;7.
    065                 */
    066                OPPOSITE_MORE_RESTRICTIVE,
    067
    068                // Enums applicable to extractors and constants.
    069
    070                /**
    071                 * Value extracted by the first extractor is less than value extracted by the second extractor
    072                 * for any combination of parameters.
    073                 */
    074                LESS_THAN,
    075
    076                /**
    077                 * Value extracted by the first extractor is less than or equal to the value extracted by the second extractor
    078                 * for any combination of parameters.
    079                 */
    080                LESS_EQUAL,
    081
    082                /**
    083                 * Value extracted by the first extractor is more than or equal to the value extracted by the second extractor
    084                 * for any combination of parameters.
    085                 */
    086                MORE_EQUAL,
    087
    088                /**
    089                 * Value extracted by the first extractor is more than value extracted by the second extractor
    090                 * for any combination of parameters.
    091                 */
    092                MORE_THAN,
    093
    094                /**
    095                 * Value extracted by the first extractor is not equal to the value extracted by the second extractor
    096                 * for any combination of parameters. Do not mistake this with NOT_EQUAL. For boolean values (predicates) UNEQUAL is
    097                 * equivalent to OPPOSITE.
    098                 */
    099                UNEQUAL
    100        }
    101
    102        private ComparisonResult.Type type;
    103        private int[] indexMap;
    104
    105        public ComparisonResult(ComparisonResult.Type type, int[] indexMap) {
    106                this.type = type;
    107                this.indexMap = indexMap;
    108        }
    109
    110        /**
    111         * @return mapping of indices of parameter extractor to this extractor. E.g. extractors
    112         * <code>arg[0] &lt; arg[1]</code> and <code>arg[1] &gt; arg[0]</code> are equal with index mapping {1, 0}.
    113         * <code>null</code> is returned for no mapping (if extractors are <code>NOT_EQUAL</code>) and for 1 to 1 mapping.
    114         * In other words, if cr = e1.compareTo(e2),
    115         * then new MappedExtractor(e1, cr.getIndexMap()).compareTo(e2).isOneToOneMapping()==true or
    116         * return value of new MappedExtractor(e1, cr.getIndexMap()).extract() is the same as of e2.extract()
    117         */
    118        public int[] getIndexMap() {
    119                return indexMap;
    120        }
    121
    122        public Type getType() {
    123                return type;
    124        }
    125
    126        public boolean isOneToOneMapping() {
    127                return isOneToOneMapping(indexMap);
    128        }
    129
    130        public static boolean isOneToOneMapping(int[] map) {
    131                if (map==null) {
    132                        return true;
    133                }
    134                for (int i=0; i<map.length; ++i) {
    135                        if (map[i]!=i && map[i]!=-1) {
    136                                return false;
    137                        }
    138                }
    139                return true;
    140        }
    141
    142        public boolean compareIndexMaps(int[] otherIndexMap) {
    143                if (indexMap==null) { // Assumes 1-1 mapping
    144                        if (otherIndexMap==null) {
    145                                return true;
    146                        }
    147
    148                        for (int i=0; i<otherIndexMap.length; ++i) {
    149                                if (otherIndexMap[i]!=i) {
    150                                        return false;
    151                                }
    152                        }
    153                        return true;
    154                }
    155
    156                if (otherIndexMap==null) {
    157                        for (int i=0; i<indexMap.length; ++i) {
    158                                if (indexMap[i]!=i) {
    159                                        return false;
    160                                }
    161                        }
    162                        return true;
    163                }
    164
    165                return Arrays.equals(indexMap, otherIndexMap);
    166        }
    167
    168        @Override
    169        public String toString() {
    170                return "ComparisonResult [type=" + type + ", indexMap="
    171                                + Arrays.toString(indexMap) + "]";
    172        }
    173
    174        /**
    175         * Inverses index map.
    176         * @param indexMap2
    177         * @return
    178         */
    179        public static int[] inverse(int[] map, Set<Integer> parameterIndices) {
    180                if (map==null) {
    181                        return null;
    182                }
    183
    184                int dim = -1;
    185                for (int i=0; i<map.length; ++i) {
    186                        if (parameterIndices.contains(i)) {
    187                                if (map[i]>dim) {
    188                                        dim = map[i];
    189                                }
    190                        }
    191                }
    192                int[] ret = new int[dim+1];
    193
    194                for (int i=0; i<map.length; ++i) {
    195                        if (parameterIndices.contains(i)) {
    196                                ret[map[i]] = i;
    197                        }
    198                }
    199                return ret;
    200        }
    201
    202        @Override
    203        public int hashCode() {
    204                final int prime = 31;
    205                int result = 1;
    206                result = prime * result + Arrays.hashCode(indexMap);
    207                result = prime * result + ((type == null) ? 0 : type.hashCode());
    208                return result;
    209        }
    210
    211        @Override
    212        public boolean equals(Object obj) {
    213                if (this == obj)
    214                        return true;
    215                if (obj == null)
    216                        return false;
    217                if (getClass() != obj.getClass())
    218                        return false;
    219                ComparisonResult other = (ComparisonResult) obj;
    220                if (!(isOneToOneMapping() && other.isOneToOneMapping())) {
    221                        if (!Arrays.equals(indexMap, other.indexMap))
    222                                return false;
    223                }
    224
    225                if (type != other.type)
    226                        return false;
    227                return true;
    228        }
    229
    230}