001package org.clafer.ast.analysis; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.HashMap; 006import java.util.HashSet; 007import java.util.List; 008import java.util.Map; 009import java.util.Set; 010import org.clafer.ast.AstAbstractClafer; 011import org.clafer.ast.AstBoolExpr; 012import org.clafer.ast.AstClafer; 013import org.clafer.ast.AstConcreteClafer; 014import org.clafer.ast.AstConstraint; 015import org.clafer.ast.AstExpr; 016import org.clafer.ast.AstModel; 017import org.clafer.ast.AstRef; 018import org.clafer.ast.AstSetExpr; 019import org.clafer.ast.AstUtil; 020import org.clafer.ast.Card; 021import org.clafer.collection.Pair; 022import org.clafer.common.Util; 023import org.clafer.ir.IrDomain; 024import org.clafer.objective.Objective; 025import org.clafer.scope.Scopable; 026import org.clafer.scope.Scope; 027 028/** 029 * 030 * @author jimmy 031 */ 032public class Analysis { 033 034 private final AstModel model; 035 private Scope scope; 036 private Map<Objective, AstSetExpr> objectiveExprs; 037 private final List<AstClafer> clafers; 038 private final List<AstAbstractClafer> abstractClafers; 039 private final List<AstConcreteClafer> concreteClafers; 040 private final List<Set<AstClafer>> clafersInParentAndSubOrder; 041 private List<AstConstraint> constraints; 042 private Set<AstConstraint> hardConstraints; 043 private Map<AstConstraint, AstBoolExpr> constraintExprs; 044 private Map<AstConcreteClafer, Card> cardMap; 045 private Map<AstClafer, Card> globalCardMap; 046 private Map<AstClafer, Format> formatMap; 047 private Map<AstAbstractClafer, Offsets> offsetMap; 048 private Map<AstClafer, PartialSolution> partialSolutionMap; 049 private Map<AstRef, IrDomain[]> partialIntsMap; 050 private Map<AstClafer, AstConcreteClafer[]> breakableChildrenMap; 051 private Map<AstRef, int[]> breakableRefsMap; 052 private Map<AstClafer, AstRef[]> breakableTargetsMap; 053 private Map<AstExpr, Type> typeMap; 054 055 Analysis(AstModel model, Scope scope) { 056 this(model, scope, Collections.<Objective>emptyList()); 057 } 058 059 Analysis(AstModel model, Scope scope, List<Objective> objectives) { 060 this(model, scope, objectives, 061 AstUtil.getAbstractClafersInSubOrder(model), 062 AstUtil.getConcreteClafers(model), 063 AstUtil.getClafersInParentAndSubOrder(model)); 064 } 065 066 Analysis(AstModel model, Scope scope, 067 List<Objective> objectives, 068 List<AstAbstractClafer> abstractClafers, 069 List<AstConcreteClafer> concreteClafers, 070 List<Set<AstClafer>> clafersInParentAndSubOrder) { 071 this.model = model; 072 this.scope = scope; 073 this.objectiveExprs = new HashMap<>(); 074 for (Objective objective : objectives) { 075 this.objectiveExprs.put(objective, objective.getExpr()); 076 } 077 this.clafers = append(abstractClafers, concreteClafers); 078 this.abstractClafers = abstractClafers; 079 this.concreteClafers = concreteClafers; 080 this.clafersInParentAndSubOrder = clafersInParentAndSubOrder; 081 this.constraints = AstUtil.getNestedConstraints(model); 082 this.hardConstraints = new HashSet<>(constraints.size()); 083 this.constraintExprs = new HashMap<>(constraints.size()); 084 for (AstConstraint constraint : constraints) { 085 if (constraint.isHard()) { 086 hardConstraints.add(constraint); 087 } 088 constraintExprs.put(constraint, constraint.getExpr()); 089 } 090 this.cardMap = buildCardMap(clafers); 091 } 092 093 private static Map<AstConcreteClafer, Card> buildCardMap(List<AstClafer> clafers) { 094 Map<AstConcreteClafer, Card> cardMap = new HashMap<>(); 095 for (AstClafer clafer : clafers) { 096 if (clafer instanceof AstConcreteClafer) { 097 AstConcreteClafer concreteClafer = (AstConcreteClafer) clafer; 098 cardMap.put(concreteClafer, concreteClafer.getCard()); 099 } 100 } 101 return cardMap; 102 } 103 104 private static List<AstClafer> append(List<? extends AstClafer> abstractClafers, List<? extends AstConcreteClafer> concreteClafers) { 105 List<AstClafer> clafers = new ArrayList<>(abstractClafers.size() + concreteClafers.size()); 106 clafers.addAll(abstractClafers); 107 clafers.addAll(concreteClafers); 108 return clafers; 109 } 110 111 public static Analysis analyze(AstModel model, Scopable scope, Analyzer... analyzers) { 112 return analyze(model, scope, Collections.<Objective>emptyList(), analyzers); 113 } 114 115 public static Analysis analyze(AstModel model, Scopable scope, List<Objective> objectives, Analyzer... analyzers) { 116 Analysis analysis = new Analysis(model, scope.toScope(), objectives); 117 for (Analyzer analyzer : analyzers) { 118 analysis = analyzer.analyze(analysis); 119 } 120 return analysis; 121 } 122 123 private <T> T notNull(String analysisName, T t) { 124 if (t == null) { 125 throw new AnalysisException(analysisName + " not yet analyzed."); 126 } 127 return t; 128 } 129 130 private <T> T notNull(String key, String analysisName, T t) { 131 if (t == null) { 132 throw new AnalysisException(analysisName + " for " + key + " not yet analyzed."); 133 } 134 return t; 135 } 136 137 private <T> T notNull(AstClafer key, String analysisName, T t) { 138 return notNull(key.getName(), analysisName, t); 139 } 140 141 /** 142 * Returns the original model. Analyzers are forbidden to alter the original 143 * model. 144 * 145 * @return the original model 146 */ 147 public AstModel getModel() { 148 return model; 149 } 150 151 public int getScope(AstClafer clafer) { 152 return getScope().getScope(clafer); 153 } 154 155 public Scope getScope() { 156 return notNull("Scope", scope); 157 } 158 159 public Analysis setScope(Scope scope) { 160 this.scope = scope; 161 return this; 162 } 163 164 public AstSetExpr getExpr(Objective objective) { 165 return objectiveExprs.get(objective); 166 } 167 168 public Map<Objective, AstSetExpr> getObjectiveExprs() { 169 return Collections.unmodifiableMap(objectiveExprs); 170 } 171 172 public Analysis setObjectiveExprs(Map<Objective, AstSetExpr> objectiveExprs) { 173 this.objectiveExprs = objectiveExprs; 174 return this; 175 } 176 177 /** 178 * @return the Clafers in no specific order 179 */ 180 public List<AstClafer> getClafers() { 181 return Collections.unmodifiableList(clafers); 182 } 183 184 /** 185 * @return the abstract Clafers in sub-order 186 */ 187 public List<AstAbstractClafer> getAbstractClafers() { 188 return Collections.unmodifiableList(abstractClafers); 189 } 190 191 /** 192 * @return the concrete Clafers in parent-order 193 */ 194 public List<AstConcreteClafer> getConcreteClafers() { 195 return Collections.unmodifiableList(concreteClafers); 196 } 197 198 /** 199 * @return the Clafers in parent-order and sub-order 200 */ 201 public List<Set<AstClafer>> getClafersInParentAndSubOrder() { 202 return clafersInParentAndSubOrder; 203 } 204 205 public List<AstConstraint> getConstraints() { 206 return Collections.unmodifiableList(constraints); 207 } 208 209 public Analysis setConstraints(List<AstConstraint> constraints) { 210 this.constraints = constraints; 211 return this; 212 } 213 214 public boolean isHard(AstConstraint constraint) { 215 return hardConstraints.contains(constraint); 216 } 217 218 public boolean isSoft(AstConstraint constraint) { 219 return !isHard(constraint); 220 } 221 222 public Set<AstConstraint> getHardConstraints() { 223 return hardConstraints; 224 } 225 226 public Analysis setHardConstraints(Set<AstConstraint> hardConstraints) { 227 this.hardConstraints = hardConstraints; 228 return this; 229 } 230 231 public AstBoolExpr getExpr(AstConstraint constraint) { 232 return constraintExprs.get(constraint); 233 } 234 235 public Map<AstConstraint, AstBoolExpr> getConstraintExprs() { 236 return constraintExprs; 237 } 238 239 public Analysis setConstraintExprs(Map<AstConstraint, AstBoolExpr> constraintExprs) { 240 this.constraintExprs = constraintExprs; 241 return this; 242 } 243 244 public Card getCard(AstConcreteClafer clafer) { 245 return notNull(clafer, "Card", getCardMap().get(clafer)); 246 } 247 248 public Map<AstConcreteClafer, Card> getCardMap() { 249 return notNull("Card", cardMap); 250 } 251 252 public Analysis setCardMap(Map<AstConcreteClafer, Card> cardMap) { 253 this.cardMap = cardMap; 254 return this; 255 } 256 257 public Card getGlobalCard(AstClafer clafer) { 258 return notNull(clafer, "GlobalCard", getGlobalCardMap().get(clafer)); 259 } 260 261 public Map<AstClafer, Card> getGlobalCardMap() { 262 return notNull("Global card", globalCardMap); 263 } 264 265 public Analysis setGlobalCardMap(Map<AstClafer, Card> globalCardMap) { 266 this.globalCardMap = globalCardMap; 267 return this; 268 } 269 270 public Format getFormat(AstClafer clafer) { 271 return notNull(clafer, "Format", getFormatMap().get(clafer)); 272 } 273 274 public Map<AstClafer, Format> getFormatMap() { 275 return notNull("Format", formatMap); 276 } 277 278 public Analysis setFormatMap(Map<AstClafer, Format> formatMap) { 279 this.formatMap = formatMap; 280 return this; 281 } 282 283 public Pair<AstConcreteClafer, Integer> getConcreteId(AstClafer clafer, int id) { 284 AstClafer sub = clafer; 285 int curId = id; 286 while (sub instanceof AstAbstractClafer) { 287 Offsets offset = getOffsets((AstAbstractClafer) sub); 288 sub = offset.getClafer(curId); 289 curId -= offset.getOffset(sub); 290 } 291 return new Pair<>((AstConcreteClafer) sub, curId); 292 } 293 294 public Pair<AstClafer, Integer> getSubId(AstAbstractClafer clafer, int id) { 295 Offsets offsets = getOffsets(clafer); 296 AstClafer sub = offsets.getClafer(id); 297 return new Pair<>(sub, id - offsets.getOffset(sub)); 298 } 299 300 public Pair<AstAbstractClafer, Integer> getSuperId(AstClafer clafer, int id) { 301 assert clafer.hasSuperClafer(); 302 int offset = getOffsets(clafer.getSuperClafer()).getOffset(clafer); 303 return new Pair<>(clafer.getSuperClafer(), id + offset); 304 } 305 306 public List<Pair<AstAbstractClafer, Integer>> getSuperIds(AstClafer clafer, int id) { 307 List<Pair<AstAbstractClafer, Integer>> superIds = new ArrayList<>(); 308 AstClafer sup = clafer; 309 int curId = id; 310 while (sup.hasSuperClafer()) { 311 Pair<AstAbstractClafer, Integer> superId = getSuperId(sup, curId); 312 superIds.add(superId); 313 sup = superId.getFst(); 314 curId = superId.getSnd().intValue(); 315 } 316 return superIds; 317 } 318 319 public List<Pair<AstClafer, Integer>> getHierarcyOffsets(AstClafer clafer) { 320 return getHierarcyIds(clafer, 0); 321 } 322 323 public List<Pair<AstClafer, Integer>> getHierarcyIds(AstClafer clafer, int id) { 324 List<Pair<AstClafer, Integer>> superIds = new ArrayList<>(); 325 superIds.add(new Pair<>(clafer, id)); 326 AstClafer sup = clafer; 327 int curId = id; 328 while (sup.hasSuperClafer()) { 329 Pair<AstAbstractClafer, Integer> superId = getSuperId(sup, curId); 330 superIds.add(new Pair<AstClafer, Integer>(superId)); 331 sup = superId.getFst(); 332 curId = superId.getSnd().intValue(); 333 } 334 return superIds; 335 } 336 337 public Pair<AstRef, Integer> getInheritedRefId(AstClafer clafer) { 338 AstClafer sup = clafer; 339 int curId = 0; 340 do { 341 if (sup.hasRef()) { 342 return new Pair<>(sup.getRef(), curId); 343 } 344 if (sup.hasSuperClafer()) { 345 curId += getOffsets(sup.getSuperClafer()).getOffset(sup); 346 } 347 sup = sup.getSuperClafer(); 348 } while (sup != null); 349 return null; 350 } 351 352 public Offsets getOffsets(AstAbstractClafer clafer) { 353 return notNull(clafer, "Offset", getOffsetMap().get(clafer)); 354 } 355 356 public Map<AstAbstractClafer, Offsets> getOffsetMap() { 357 return notNull("Offset", offsetMap); 358 } 359 360 public Analysis setOffsetMap(Map<AstAbstractClafer, Offsets> offsetMap) { 361 this.offsetMap = offsetMap; 362 return this; 363 } 364 365 public PartialSolution getPartialSolution(AstClafer clafer) { 366 return notNull(clafer, "Partial solution", getPartialSolutionMap().get(clafer)); 367 } 368 369 public Map<AstClafer, PartialSolution> getPartialSolutionMap() { 370 return notNull("Partial solution", partialSolutionMap); 371 } 372 373 public Analysis setPartialSolutionMap(Map<AstClafer, PartialSolution> partialSolutionMap) { 374 this.partialSolutionMap = partialSolutionMap; 375 return this; 376 } 377 378 public IrDomain[] getPartialInts(AstRef ref) { 379 return notNull(ref.getSourceType(), "Partial integer", getPartialIntsMap().get(ref)); 380 } 381 382 public Map<AstRef, IrDomain[]> getPartialIntsMap() { 383 return notNull("Partial integer", partialIntsMap); 384 } 385 386 public Analysis setPartialIntsMap(Map<AstRef, IrDomain[]> partialIntsMap) { 387 this.partialIntsMap = partialIntsMap; 388 return this; 389 } 390 391 public boolean hasInteritedBreakableChildren(AstClafer clafer) { 392 AstClafer sup = clafer; 393 do { 394 if (hasBreakableChildren(sup)) { 395 return true; 396 } 397 sup = sup.getSuperClafer(); 398 } while (sup != null); 399 return false; 400 } 401 402 public boolean hasBreakableChildren(AstClafer clafer) { 403 return getBreakableChildren(clafer).length > 0; 404 } 405 406 public AstConcreteClafer[] getBreakableChildren(AstClafer clafer) { 407 return notNull("Breakable children", getBreakableChildrenMap().get(clafer)); 408 } 409 410 public Map<AstClafer, AstConcreteClafer[]> getBreakableChildrenMap() { 411 return notNull("Breakable children", breakableChildrenMap); 412 } 413 414 public Analysis setBreakableChildrenMap(Map<AstClafer, AstConcreteClafer[]> breakableChildren) { 415 this.breakableChildrenMap = breakableChildren; 416 return this; 417 } 418 419 public boolean isBreakableRef(AstRef ref) { 420 return getBreakableRefsMap().containsKey(ref); 421 } 422 423 public boolean isBreakableRefId(AstRef ref, int id) { 424 int[] breakbleIDs = getBreakableRefsMap().get(ref); 425 if (breakbleIDs == null) { 426 return false; 427 } 428 return Util.in(id, breakbleIDs); 429 } 430 431 public Map<AstRef, int[]> getBreakableRefsMap() { 432 return notNull("Breakable ref", breakableRefsMap); 433 } 434 435 public Analysis setBreakableRefsMap(Map<AstRef, int[]> breakableRefs) { 436 this.breakableRefsMap = breakableRefs; 437 return this; 438 } 439 440 public boolean isInheritedBreakableTarget(AstClafer clafer) { 441 AstClafer sup = clafer; 442 do { 443 if (isBreakableTarget(sup)) { 444 return true; 445 } 446 sup = sup.getSuperClafer(); 447 } while (sup != null); 448 return false; 449 } 450 451 public boolean isBreakableTarget(AstClafer clafer) { 452 return getBreakableTargetsMap().containsKey(clafer); 453 } 454 455 public AstRef[] getBreakableTarget(AstClafer clafer) { 456 AstRef[] ref = getBreakableTargetsMap().get(clafer); 457 return ref == null ? new AstRef[0] : ref; 458 } 459 460 public Map<AstClafer, AstRef[]> getBreakableTargetsMap() { 461 return notNull("Breakable target", breakableTargetsMap); 462 } 463 464 public Analysis setBreakableTargetsMap(Map<AstClafer, AstRef[]> breakableTargetsMap) { 465 this.breakableTargetsMap = breakableTargetsMap; 466 return this; 467 } 468 469 public Type getType(AstExpr expr) { 470 return notNull(expr.toString(), "Type", getTypeMap().get(expr)); 471 } 472 473 public AstClafer getCommonSupertype(AstExpr expr) { 474 return notNull(expr.toString(), "Type", getTypeMap().get(expr)).getCommonSuperType(); 475 } 476 477 public Map<AstExpr, Type> getTypeMap() { 478 return notNull("Type", typeMap); 479 } 480 481 public Analysis setTypeMap(Map<AstExpr, Type> typeMap) { 482 this.typeMap = typeMap; 483 return this; 484 } 485}