package kodkod.engine.bool; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import kodkod.ast.Variable; import kodkod.ast.operator.Quantifier; import kodkod.engine.fol2sat.Environment; public class DefCond { /* ------------------------------------------------------------------------------------ */ /* used during translation */ /* ------------------------------------------------------------------------------------ */ private BooleanValue overflow = BooleanConstant.FALSE; private BooleanValue accumOverflow = BooleanConstant.FALSE; private Set<Variable> vars = new HashSet<Variable>(); public BooleanValue getOverflow() { return overflow; } public BooleanValue getAccumOverflow() { return accumOverflow; } public void setOverflows(BooleanValue of, BooleanValue accumOF) { this.overflow = of; this.accumOverflow = accumOF; } public void addVar(Variable v) { vars.add(v); } public void addVars(Collection<Variable> vars) { this.vars.addAll(vars); } public Set<Variable> vars() { return vars; } /** * ORs overflow circuits of <code>this</code> object ( * <code>this.mergedOverflow</code>), a given <code>other</code> object ( * <code>other.mergedOverflow</code>), and a given overflow circuit ( * <code>of</code>) */ public static BooleanValue merge(BooleanFactory factory, BooleanValue accum, DefCond ... conds) { BooleanValue ret = accum; for (DefCond dc : conds) { ret = factory.or(ret, dc.accumOverflow); } return ret; } public static BooleanValue merge(BooleanFactory factory, DefCond ... conds) { return merge(factory, BooleanConstant.FALSE, conds); } /** * If overflow checking is disabled returns <code>value</code>. Otherwise, * returns a conjunction of <code>value</code>, <code>lhs.accumOverflow</code>, * and <code>rhs.accumOverflow</code>. * * ~~~ NOTE ~~~: Every time a BooleanValue is returned as a result of an operation * over Ints, one of the <code>ensureNoOverflow</code> methods * should be called. */ public static BooleanValue ensureDef(BooleanFactory factory, Environment<?, ?> env, BooleanValue value, DefCond ... dcs) { if (!factory.noOverflow) return value; List<DefCond> univQuantInts = new ArrayList<DefCond>(dcs.length); List<DefCond> extQuantInts = new ArrayList<DefCond>(dcs.length); for (DefCond e : dcs) { if (isUnivQuant(env, e)) univQuantInts.add(e); else extQuantInts.add(e); } BooleanValue ret = value; if (!env.isNegated()) { for (DefCond e : extQuantInts) ret = factory.and(ret, factory.not(e.getAccumOverflow())); for (DefCond e : univQuantInts) ret = factory.or(ret, e.getAccumOverflow()); } else { for (DefCond e : extQuantInts) ret = factory.or(ret, e.getAccumOverflow()); for (DefCond e : univQuantInts) ret = factory.and(ret, factory.not(e.getAccumOverflow())); } return ret; } private static boolean isUnivQuant(Environment<?, ?> env, DefCond e) { if (env.isEmpty()) return false; // if (!isInt(env.type())) // return isUnivQuant(env.parent(), e); if (e.vars().contains(env.variable())) { return env.envType() == Quantifier.ALL; } else { return isUnivQuant(env.parent(), e); } } // /** // * Returns if this expression represents the Int type. // */ // private static boolean isInt(Object expression) { // if (expression == null) // return false; // if (!(expression instanceof Expression)) // return false; // // TODO: this is probably not complete // return "ints".equals(expression.toString()); // } /* ------------------------------------------------------------------------------------ */ /* used by the evaluator */ /* ------------------------------------------------------------------------------------ */ private boolean isOverflowFlag = false; public void setOverflowFlag(boolean overflow) { this.isOverflowFlag = overflow; } public boolean isOverflowFlag() { return this.isOverflowFlag; } }