001package com.hammurapi.extract; 002 003import java.io.Serializable; 004import java.util.Collections; 005import java.util.HashSet; 006import java.util.Map; 007import java.util.Set; 008import java.util.TreeSet; 009import java.util.concurrent.TimeUnit; 010 011 012/** 013 * Commutative AND. 014 * @author Pavel Vlasov. 015 * 016 * @param <T> 017 */ 018public class CommutativeAnd<T, C> extends ExtractorBase<T, Boolean, C> implements CommutativeCompositePredicate<T, C, CommutativeAnd<T,C>>, Serializable { 019 020 private Set<Predicate<T, C>> parts = new HashSet<Predicate<T, C>>(); 021 022 public CommutativeAnd(double initialCost, TimeUnit costUnit) { 023 super(initialCost,costUnit); 024 } 025 026 public CommutativeAnd(double initialCost, TimeUnit costUnit, Predicate<T,C>... parts) { 027 super(initialCost,costUnit); 028 for (Predicate<T,C> part: parts) { 029 addPart(part); 030 } 031 } 032 033 public CommutativeAnd(double initialCost, TimeUnit costUnit, Iterable<Predicate<T,C>> parts) { 034 super(initialCost,costUnit); 035 for (Predicate<T,C> part: parts) { 036 addPart(part); 037 } 038 } 039 040 private void addPart(Predicate<T, C> part) { 041 if (part instanceof CommutativeAnd) { 042 for (Predicate<T, C> pp: ((CommutativeAnd<T, C>) part).getParts()) { 043 addPart(pp); 044 } 045 } else { 046 parts.add(part); 047 } 048 } 049 050 public Set<Predicate<T, C>> getParts() { 051 return Collections.unmodifiableSet(parts); 052 } 053 054 @Override 055 @SuppressWarnings("unchecked") 056 public ComparisonResult compareTo(Extractor<T, Boolean, C> otherPredicate) { 057 if (getParts().isEmpty()) { 058 return True.getInstance().compareTo((Extractor<Object, Boolean, Object>) otherPredicate); 059 } 060 061 if (otherPredicate instanceof CommutativeAnd && parts.equals(((CommutativeAnd) otherPredicate).parts)) { 062 return ComparisonResult.EQUAL_NM; 063 } 064 065 boolean isTrue = true; 066 boolean isFalse = false; 067 for (Predicate<T, C> part: getParts()) { 068 ComparisonResult pcr = part.compareTo((Predicate<T, C>) False.getInstance()); 069 if (pcr.getType().equals(ComparisonResult.Type.EQUAL)) { 070 isFalse = true; 071 isTrue = false; 072 break; 073 } else if (!pcr.getType().equals(ComparisonResult.Type.OPPOSITE)) { 074 isTrue = false; 075 } 076 } 077 078 if (isTrue) { 079 return otherPredicate.compareTo((Predicate<T, C>) True.getInstance()); 080 } 081 082 if (isFalse) { 083 return otherPredicate.compareTo((Predicate<T, C>) False.getInstance()); 084 } 085 086 if (getParts().size()==1) { 087 return getParts().iterator().next().compareTo(otherPredicate); 088 } 089 for (Predicate<T, C> part: getParts()) { 090 ComparisonResult pcr = part.compareTo(otherPredicate); 091 if (pcr.isOneToOneMapping()) { 092 switch (pcr.getType()) { 093 case EQUAL: 094 case MORE_RESTRICTIVE: 095 return ComparisonResult.MORE_RESTRICTIVE_NM; 096// case OPPOSITE: 097// case OPPOSITE_MORE_RESTRICTIVE: 098// return ComparisonResult.OPPOSITE_MORE_RESTRICTIVE_NM; 099 } 100 } 101 } 102 103 return super.compareTo(otherPredicate); 104 } 105 106 protected Boolean extractInternal(C context, Map<C, Map<Extractor<T, ? super Boolean, C>, ? super Boolean>> cache, T... obj) { 107 for (Predicate<T, C> part: parts) { 108 if (!part.extract(context, cache, obj)) { 109 return false; 110 } 111 } 112 return true; 113 } 114 115 public Set<Integer> parameterIndices() { 116 Set<Integer> ret = new TreeSet<Integer>(); 117 for (Predicate<T, C> part: parts) { 118 ret.addAll(part.parameterIndices()); 119 } 120 return ret; 121 } 122 123 124 @SuppressWarnings("unchecked") 125 public Predicate<T, C> remove(Predicate<T, C> part) { 126 if (!parts.contains(part)) { 127 return this; 128 } 129 try { 130 CommutativeAnd<T, C> ret = (CommutativeAnd<T, C>) clone(); 131 ret.parts.remove(part); 132 return ret.parts.size()==1 ? ret.parts.iterator().next() : ret; 133 } catch (CloneNotSupportedException e) { 134 throw new ExtractorException(e); 135 } 136 } 137 138 @SuppressWarnings("unchecked") 139 public Predicate<T, C> normalize() { 140 if (getParts().isEmpty()) { 141 return True.getInstance(); 142 } 143 if (getParts().size()==1) { 144 Predicate<T, C> ret = getParts().iterator().next(); 145 if (ret instanceof CompositePredicate) { 146 ((CompositePredicate) ret).normalize(); 147 } 148 return ret; 149 } 150 ComparisonResult cr = compareTo((Predicate<T, C>) True.getInstance()); 151 if (cr.getType().equals(ComparisonResult.Type.EQUAL)) { 152 return True.getInstance(); 153 } 154 if (cr.getType().equals(ComparisonResult.Type.OPPOSITE)) { 155 return False.getInstance(); 156 } 157 Predicate<T, C>[] pa = getParts().toArray(new Predicate[getParts().size()]); 158 Z: for (int i=0; i<pa.length; ++i) { 159 for (int j=0; j<pa.length; ++j) { 160 if (j!=i && pa[i]!=null && pa[j]!=null) { 161 ComparisonResult pcr1 = pa[i].compareTo(pa[j]); 162 if (pcr1.isOneToOneMapping()) { 163 switch (pcr1.getType()) { 164 case EQUAL: 165 case LESS_RESTRICTIVE: 166 pa[j]=null; 167 continue; 168 case OPPOSITE: 169 case OPPOSITE_LESS_RESTRICTIVE: 170 return False.getInstance(); 171 } 172 } 173 174 ComparisonResult pcr2 = pa[j].compareTo(pa[i]); 175 if (pcr2.isOneToOneMapping()) { 176 switch (pcr2.getType()) { 177 case EQUAL: 178 case LESS_RESTRICTIVE: 179 pa[i]=null; 180 continue Z; 181 case OPPOSITE: 182 case OPPOSITE_LESS_RESTRICTIVE: 183 return False.getInstance(); 184 } 185 } 186 } 187 } 188 } 189 190 int pc = 0; 191 for (Predicate<T, C> part: pa) { 192 if (part!=null) { 193 ++pc; 194 } 195 } 196 197 if (pc==0) { 198 return True.getInstance(); 199 } 200 201 if (pc==1) { 202 for (Predicate<T, C> part: pa) { 203 if (part!=null) { 204 if (part instanceof CompositePredicate) { 205 ((CompositePredicate) part).normalize(); 206 } 207 return part; 208 } 209 } 210 } 211 212 if (pc!=pa.length) { 213 CommutativeAnd<T, C> ret = new CommutativeAnd<T, C>(cost, costUnit); 214 for (Predicate<T, C> part: pa) { 215 if (part!=null) { 216 ret.addPart(part); 217 } 218 } 219 return ret; 220 } 221 222 return this; 223 } 224 225 public boolean isContextDependent() { 226 for (Predicate<T, C> part: getParts()) { 227 if (part.isContextDependent()) { 228 return true; 229 } 230 } 231 return false; 232 } 233 234 @Override 235 public String toString() { 236 return getClass().getName()+getParts(); 237 } 238 239 @Override 240 public double getCost() { 241 if (cost==0 && costUnit==null) { 242 double ret = 0; 243 for (Predicate<T,C> part: parts) { 244 ret+=part.getCost(); 245 } 246 return ret; 247 } 248 return super.getCost(); 249 } 250 251 252 @Override 253 public Extractor<T, Boolean, C> map(int[] map) { 254 CommutativeAnd<T,C> ret = new CommutativeAnd<T, C>(initialCost, costUnit); 255 for (Predicate<T,C> part: parts) { 256 ret.addPart(MappedPredicate.mapPredicate(part, map)); 257 } 258 return ret; 259 } 260 261 @Override 262 public Object clone() throws CloneNotSupportedException { 263 @SuppressWarnings("unchecked") 264 CommutativeAnd<T,C> ret = (CommutativeAnd<T, C>) super.clone(); 265 ret.parts = new HashSet<Predicate<T,C>>(parts); 266 return ret; 267 } 268 269 @Override 270 public CommutativeAnd<T, C> add(Predicate<T, C> part) { 271 CommutativeAnd<T, C> ret = new CommutativeAnd<T, C>(initialCost, costUnit, parts); 272 ret.parts.add(part); 273 return ret; 274 } 275}