def addGroupCardConstraints(self): self.upperGCard = self.element.gcard.interval[1].value self.lowerGCard = self.element.gcard.interval[0].value if (len(self.fields) == 0 and ((not self.superSort) or self.superSort.fields == 0)): return #lower bounds if not self.fields: return # front end is broken if self.lowerGCard == 0 and self.upperGCard == -1: return for i in range(self.numInstances): bigSumm = SMTLib.SMT_IntConst(0) for j in self.fields: bigSumm = SMTLib.SMT_Plus(bigSumm, j.summs[i]) #**** LEAVE THIS CODE **** #don't include inherited fields for now #if self.superSort: # for j in self.superSort.fields: # print("found " + str(j)) # bigSumm = bigSumm + j.summs[i + self.indexInSuper] if self.lowerGCard != 0: self.constraints.addGroupCardConstraint( SMTLib.SMT_Implies( self.isOn(i), SMTLib.SMT_GE(bigSumm, SMTLib.SMT_IntConst(self.lowerGCard)))) if self.upperGCard != -1: self.constraints.addGroupCardConstraint( SMTLib.SMT_Implies( self.isOn(i), SMTLib.SMT_LE(bigSumm, SMTLib.SMT_IntConst(self.upperGCard))))
def ConstraintNotDominatedByX(self, model): """ Creates a constraint preventing search in dominated regions. """ DisjunctionOrLessMetrics = list() for i in range(len(self.metrics_variables)): if self.metrics_objective_direction[i] == Common.METRICS_MAXIMIZE: DisjunctionOrLessMetrics.append( SMTLib.SMT_GT( self.metrics_variables[i], SMTLib.SMT_IntConst( Common.evalForNum( model, self.metrics_variables[i].convert( self.cfr.solver.converter)))) ) #model[self.metrics_variables[i]]) else: DisjunctionOrLessMetrics.append( SMTLib.SMT_LT( self.metrics_variables[i], SMTLib.SMT_IntConst( Common.evalForNum( model, self.metrics_variables[i].convert( self.cfr.solver.converter)))) ) #model[self.metrics_variables[i]]) return SMTLib.SMT_Or(*DisjunctionOrLessMetrics)
def op_card(arg): ''' :param arg: :type left: :class:`~arg` :param right: :type right: :class:`~ExprArg` :returns: :class:`~IntArg` Returns the number of instances that are *on* in arg. ''' assert isinstance(arg, ExprArg) instances = [] matches = getSetInstancePairs(arg) known_card = 0 if arg.getInts(): card_cons = compute_int_set(arg.getInts()) for i in card_cons: if isinstance(i, SMTLib.SMT_BoolConst): if i.value: known_card = known_card + 1 else: instances.append( SMTLib.SMT_If(i, SMTLib.SMT_IntConst(1), SMTLib.SMT_IntConst(0))) for (instance, _) in matches.values(): (expr, polarity) = instance if polarity == Common.DEFINITELY_ON: known_card = known_card + 1 else: instances.append( SMTLib.SMT_If(expr, SMTLib.SMT_IntConst(1), SMTLib.SMT_IntConst(0))) instances.append(SMTLib.SMT_IntConst(known_card)) return IntArg(SMTLib.createSum(instances))
def ConstraintMustDominatesX(self, model): """ Returns a constraint that a new instance has to be better than the instance represented by model in at least one dimension, and better or equal in all the other ones. """ dominationDisjunction = [] i = 0 for dominatedByMetric in self.metrics_variables: dominationConjunction = [] j = 0 if self.metrics_objective_direction[i] == Common.METRICS_MAXIMIZE: dominationConjunction.append( SMTLib.SMT_GT( dominatedByMetric, SMTLib.SMT_IntConst( Common.evalForNum( model, dominatedByMetric.convert( self.cfr.solver.converter))))) else: dominationConjunction.append( SMTLib.SMT_LT( dominatedByMetric, SMTLib.SMT_IntConst( Common.evalForNum( model, dominatedByMetric.convert( self.cfr.solver.converter))))) for AtLeastEqualInOtherMetric in self.metrics_variables: if j != i: if self.metrics_objective_direction[ j] == Common.METRICS_MAXIMIZE: dominationConjunction.append( SMTLib.SMT_GE( AtLeastEqualInOtherMetric, SMTLib.SMT_IntConst( Common.evalForNum( model, AtLeastEqualInOtherMetric.convert( self.cfr.solver.converter))))) else: dominationConjunction.append( SMTLib.SMT_LE( AtLeastEqualInOtherMetric, SMTLib.SMT_IntConst( Common.evalForNum( model, AtLeastEqualInOtherMetric.convert( self.cfr.solver.converter))))) j = 1 + j i = 1 + i dominationDisjunction.append( SMTLib.SMT_And(*dominationConjunction)) constraintDominateX = SMTLib.SMT_Or(*dominationDisjunction) return constraintDominateX
def isOff(self, index): ''' Returns a Boolean Constraint stating whether or not the instance at the given index is *off*. An instance is off if it is set to self.parentInstances. ''' try: return SMTLib.SMT_EQ(self.instances[index], SMTLib.SMT_IntConst(self.parentInstances)) except: return SMTLib.SMT_EQ(index, SMTLib.SMT_IntConst(self.parentInstances))
def isOn(self, index): ''' index is either an int or SMT-Int Returns a Boolean Constraint stating whether or not the instance at the given index is *on*. An instance is on if it is not set to self.parentInstances. ''' try: return SMTLib.SMT_NE(self.instances[index], SMTLib.SMT_IntConst(self.parentInstances)) except: return SMTLib.SMT_NE(index, SMTLib.SMT_IntConst(self.parentInstances))
def quant_one(exprs, ifConstraints): ''' There's probably a better way to do this. ''' condList = getQuantifierConditionList(exprs) if ifConstraints: condList = [mAnd(i, j) for i, j in zip(ifConstraints, condList)] exprList = [] for i in range(len(condList)): exprList.append( SMTLib.SMT_If(condList[i], SMTLib.SMT_IntConst(1), SMTLib.SMT_IntConst(0))) return SMTLib.SMT_EQ(SMTLib.createSum(*exprList), SMTLib.SMT_IntConst(1))
def joinWithClafer(left, right): newInstances = {} leftInstances = left.getInstances(nonsupered=True) rightInstances = right.getInstances(nonsupered=True) for (lsort, lindex) in leftInstances.keys(): (lexpr, lpolarity) = leftInstances[(lsort, lindex)] if lpolarity == Common.DEFINITELY_OFF: continue for (rsort, rindex) in rightInstances.keys(): (_rexpr, rpolarity) = rightInstances[(rsort, rindex)] if rpolarity == Common.DEFINITELY_OFF: continue noMatch = False while not (rsort in lsort.fields): if not lsort.superSort: noMatch = True break (lsort, lindex) = joinWithSuper(lsort, lindex) if noMatch: continue (lower, upper, _) = rsort.instanceRanges[rindex] (new_rexpr, new_rpol) = newInstances.get((rsort, rindex), ({}, {})) new_rpol[lindex] = lpolarity new_rexpr[lindex] = mAnd( lexpr, SMTLib.SMT_EQ(rsort.instances[rindex], SMTLib.SMT_IntConst(lindex))) if lower <= lindex and lindex <= upper: newInstances[(rsort, rindex)] = (new_rexpr, new_rpol) newInstances = flattenInstances(newInstances) return ExprArg(newInstances, nonsupered=True)
def joinWithParent(arg): instances = arg.getInstances(nonsupered=True) newInstances = {} for (sort, index) in instances.keys(): (expr, pol) = instances[(sort, index)] if pol == Common.DEFINITELY_OFF: continue (lower, upper, _) = sort.instanceRanges[index] for i in range(lower, min(sort.parentInstances, upper + 1)): (old_expr, old_pol) = newInstances.get( (sort.parent, i), (SMTLib.SMT_BoolConst(False), Common.DEFINITELY_OFF)) if pol == Common.DEFINITELY_ON and lower == upper: new_pol = Common.DEFINITELY_ON new_expr = SMTLib.SMT_BoolConst(True) else: new_pol = Common.aggregate_polarity(old_pol, Common.UNKNOWN) new_expr = mOr( old_expr, mAnd( expr, SMTLib.SMT_EQ(sort.instances[index], SMTLib.SMT_IntConst(i)))) newInstances[(sort.parent, i)] = (new_expr, new_pol) return ExprArg(newInstances, nonsupered=True)
def putIfNotMatched(sort, mask, index, value, matches): ''' Used to make sure you don't add duplicate elements to a set i.e. a sub and super. Needed by union, intersection, and difference. ''' if not matches: mask.put(index, value) else: cond = [] for i in matches: (leftIsSub, transform, (match_sort, match_mask)) = i if leftIsSub: if match_mask.get(index + transform): cond.append( match_sort.isOff(match_mask.get(index + transform))) else: if match_mask.get(index - transform): cond.append( match_sort.isOff(match_mask.get(index - transform))) if not cond: mask.put(index, value) else: mask.put( index, SMTLib.SMT_If(mAnd(*cond), value, SMTLib.SMT_IntConst(sort.parentInstances)))
def int_set_in(leftIntSort, rightIntSort): (left_sort, left_mask) = leftIntSort (right_sort, right_mask) = rightIntSort cond = [] for i in left_mask.keys(): constraint = SMTLib.SMT_Or( SMTLib.SMT_EQ(left_sort.cardinalityMask.get(i), SMTLib.SMT_IntConst(0)), SMTLib.SMT_Or(*[ SMTLib.SMT_And( SMTLib.SMT_EQ(right_sort.cardinalityMask.get(j), SMTLib.SMT_IntConst(1)), SMTLib.SMT_EQ(right_mask.get(j), left_mask.get(i))) for j in right_mask.keys() ])) cond.append(constraint) return (SMTLib.SMT_And(*cond))
def createInstancesConstraintsAndFunctions(self): for i in range(self.numInstances): (lower, upper, extraAbsenceConstraint) = self.instanceRanges[i] #lower == upper case (simpler) if lower == upper: constraint = SMTLib.SMT_EQ(self.instances[i], SMTLib.SMT_IntConst(upper)) if extraAbsenceConstraint: self.constraints.addInstanceConstraint( SMTLib.SMT_Or(self.isOff(i), constraint)) else: #TODO self.instances[i] = SMTLib.SMT_IntConst(lower) self.constraints.addInstanceConstraint(constraint) else: #parent pointer is >= lower self.constraints.addInstanceConstraint( SMTLib.SMT_GE(self.instances[i], SMTLib.SMT_IntConst(lower))) constraint = SMTLib.SMT_LE(self.instances[i], SMTLib.SMT_IntConst(upper)) if extraAbsenceConstraint: #parent pointer is <= upper , or equal to parentInstances self.constraints.addInstanceConstraint( SMTLib.SMT_Or(self.isOff(i), constraint)) else: #parent pointer is <= upper self.constraints.addInstanceConstraint(constraint) #sorted parent pointers (only consider things that are not part of an abstract) if not self.beneathAnAbstract: if i != self.numInstances - 1: self.constraints.addInstanceConstraint( SMTLib.SMT_LE(self.instances[i], self.instances[i + 1])) if not self.parent: return #if the parent is not live, then no child can point to it for i in range(self.parent.numInstances): for j in range(self.numInstances): self.constraints.addInstanceConstraint( SMTLib.SMT_Implies( self.parent.isOff(i), SMTLib.SMT_NE(self.instances[j], SMTLib.SMT_IntConst(i))), self.parent.known_polarity(i, local=True) != Common.DEFINITELY_ON)
def op_le(left, right): ''' :param left: :type left: :class:`~ExprArg` :param right: :type right: :class:`~ExprArg` :returns: :class:`~BoolArg` Invariant: left and right have exactly one int Ensures that the left <= right. ''' assert isinstance(left, ExprArg) assert isinstance(right, ExprArg) lval = left.getInts() lval = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in lval] rval = right.getInts() rval = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in rval] lsum = SMTLib.createSum(lval) rsum = SMTLib.createSum(rval) return BoolArg(SMTLib.SMT_LE(lsum, rsum))
def op_mul(left, right): ''' :param left: :type left: :class:`~ExprArg` :param right: :type right: :class:`~ExprArg` :returns: :class:`~IntArg` Returns left * right. ''' assert isinstance(left, ExprArg) assert isinstance(right, ExprArg) lval = left.getInts() lval = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in lval] lval = SMTLib.createSum(lval) rval = right.getInts() rval = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in rval] rval = SMTLib.createSum(rval) return IntArg(SMTLib.SMT_Times(lval, rval))
def preventSameModel(cfr, solver, model): block = [] for i in cfr.cfr_sorts.values(): for j in i.instances: block.append( SMTLib.SMT_NE(j, SMTLib.SMT_IntConst(int(str(model[j.var]))))) if i.refs: for j in i.refs: try: val = model[j.var] except: #happens if a primitive ref is totally unrestricted continue if not val: continue else: block.append(SMTLib.SMT_NE(j, SMTLib.SMT_IntConst(val))) if block == []: solver.add(SMTLib.SMT_BoolConst(False)) else: solver.add(SMTLib.SMT_Or(*block))
def op_un_minus(arg): ''' :param arg: :type arg: :class:`~ExprArg` :returns: :class:`~IntArg` Negates arg. ''' assert isinstance(arg, IntArg) val = arg.getInts() val = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in val] val_sum = SMTLib.createSum(val) return IntArg(SMTLib.createNeg(val_sum))
def op_sum(arg): ''' :param arg: :type arg: :class:`~ExprArg` :returns: :class:`~IntArg` Computes the sum of all integer instances in arg. May not match the semantics of the Alloy backend. ''' assert isinstance(arg, ExprArg) sum_list = [] for (e, c) in arg.getInts(): sum_list.append(SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0))) return IntArg(SMTLib.createSum(sum_list))
def op_div(left, right): ''' :param left: :type left: :class:`~ExprArg` :param right: :type right: :class:`~ExprArg` :returns: :class:`~IntArg` Returns left / right. ''' assert isinstance(left, ExprArg) assert isinstance(right, ExprArg) lval = left.getInts() lval = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in lval] lval = SMTLib.createSum(lval) rval = right.getInts() rval = [SMTLib.createIf(c, e, SMTLib.SMT_IntConst(0)) for (e, c) in rval] rval = SMTLib.createSum(rval) return IntArg( SMTLib.SMT_Divide(lval, rval) if ( (not isinstance(lval, SMTLib.SMT_IntConst)) or ( not isinstance(rval, SMTLib.SMT_IntConst)) ) else SMTLib.SMT_IntDivide(lval, rval))
def createCardinalityConstraints(self): if not self.cfr.isUsed(self.element): return self.summs = [[] for i in range(self.parentInstances + 1)] for i in range(self.numInstances): (lower, upper, _) = self.getInstanceRange(i) for j in range(lower, upper + 1): self.summs[j].append( SMTLib.SMT_If( SMTLib.SMT_EQ(self.instances[i], SMTLib.SMT_IntConst(j)), SMTLib.SMT_IntConst(1), SMTLib.SMT_IntConst(0))) for i in range(len(self.summs)): if self.summs[i]: self.summs[i] = SMTLib.createSum(*[self.summs[i]]) else: self.summs[i] = SMTLib.SMT_IntConst(0) for i in range(self.parentInstances): if self.parent: self.constraints.addCardConstraint( SMTLib.SMT_Implies( self.parent.isOn(i), SMTLib.SMT_GE( self.summs[i], SMTLib.SMT_IntConst(self.lowerCardConstraint)))) if self.upperCardConstraint != -1: self.constraints.addCardConstraint( SMTLib.SMT_Implies( self.parent.isOn(i), SMTLib.SMT_LE( self.summs[i], SMTLib.SMT_IntConst( self.upperCardConstraint)))) else: self.constraints.addCardConstraint( SMTLib.SMT_GE( self.summs[i], SMTLib.SMT_IntConst(self.lowerCardConstraint))) if self.upperCardConstraint != -1: self.constraints.addCardConstraint( SMTLib.SMT_LE( self.summs[i], SMTLib.SMT_IntConst(self.upperCardConstraint)))
def goalVisit(self, element): bracketedConstraintsVisitor = CreateBracketedConstraints.CreateBracketedConstraints( self.cfr) op = element.exp.iExp[0].operation if op == "min": op = Common.METRICS_MINIMIZE else: op = Common.METRICS_MAXIMIZE expr = bracketedConstraintsVisitor.objectiveVisit( element.exp.iExp[0].elements[0]) if isinstance(expr[0], JoinArg): #TODO cache stuff here too (pass cfr into computeJoin if caching expr = operations.Join.computeJoin(expr) valueList = [ SMTLib.createIf(c, i, SMTLib.SMT_IntConst(0)) for (i, c) in expr.getInts() ] self.cfr.objectives.append((op, SMTLib.createSum(valueList)))
def joinWithClaferRef(arg): instances = arg.getInstances(nonsupered=True) newArg = ExprArg(nonsupered=True) for (sort, index) in instances.keys(): (expr, pol) = instances[(sort, index)] while not sort.refSort: (sort, index) = joinWithSuper(sort, index) if isinstance(sort.refSort, PrimitiveType): joinWithPrimitive(newArg, sort, index, expr, pol) else: for i in range(sort.refSort.numInstances): (prev_expr, _) = newArg.getInstances(nonsupered=True).get( (sort.refSort, i), (SMTLib.SMT_BoolConst(False), Common.DEFINITELY_OFF)) newArg.getInstances(nonsupered=True)[(sort.refSort, i)] = (mOr( prev_expr, mAnd( expr, SMTLib.SMT_EQ( sort.refs[index], SMTLib.SMT_IntConst(i)))), Common.UNKNOWN) return newArg
def addRefConstraints(self): if not self.refSort: return elif isinstance(self.refSort, PrimitiveType) and self.refSort.type == "real": self.refs = SMTLib.SMT_RealVector(self.element.uid + "_ref", self.numInstances) elif isinstance(self.refSort, PrimitiveType): self.refs = SMTLib.SMT_IntVector(self.element.uid + "_ref", self.numInstances) else: self.refs = SMTLib.SMT_IntVector( self.element.uid + "_ref", self.numInstances, bits=self.getBits(self.refSort.parentInstances + 1)) if not isinstance(self.refSort, PrimitiveType): for i in range(self.numInstances): #refs pointer is >= 0 self.constraints.addRefConstraint( SMTLib.SMT_GE(self.refs[i], SMTLib.SMT_IntConst(0))) #ref pointer is <= upper card of ref parent self.constraints.addRefConstraint( SMTLib.SMT_LE( self.refs[i], SMTLib.SMT_IntConst(self.refSort.numInstances))) #if integer refs, zero out refs that do not have live parents, #if clafer refs, set equal to ref.parentInstances if not live #reference symmetry breaking if not self.element.isAbstract: for i in range(self.numInstances - 1): for j in range(i + 1, self.numInstances): if isinstance(self.refSort, PrimitiveType): self.constraints.addRefConstraint( SMTLib.SMT_Implies( SMTLib.SMT_EQ(self.instances[i], self.instances[j]), SMTLib.SMT_LE(self.refs[i], self.refs[j]))) else: self.constraints.addRefConstraint( SMTLib.SMT_Implies( mAnd( SMTLib.SMT_NE( self.refs[i], SMTLib.SMT_IntConst( self.refSort.numInstances)), SMTLib.SMT_EQ(self.instances[i], self.instances[j])), SMTLib.SMT_LE(self.refs[i], self.refs[j]))) for i in range(self.numInstances): if isinstance(self.refSort, PrimitiveType): if self.refSort == "integer": self.constraints.addRefConstraint( SMTLib.SMT_Implies( self.isOff(i), SMTLib.SMT_EQ(self.refs[i], SMTLib.SMT_IntConst(0))), self.known_polarity(i, local=True) != Common.DEFINITELY_ON) elif self.refSort == "string": if Options.STRING_CONSTRAINTS: self.constraints.addRefConstraint( SMTLib.SMT_Implies( self.isOff(i), SMTLib.SMT_EQ(self.refs[i], self.cfr.EMPTYSTRING)), self.known_polarity(i, local=True) != Common.DEFINITELY_ON) else: self.constraints.addRefConstraint( SMTLib.SMT_Implies( self.isOff(i), SMTLib.SMT_EQ(self.refs[i], SMTLib.SMT_IntConst(0))), self.known_polarity(i, local=True) != Common.DEFINITELY_ON) else: self.constraints.addRefConstraint( SMTLib.SMT_Implies( self.isOff(i), SMTLib.SMT_EQ(self.refs[i], SMTLib.SMT_IntConst(0))), self.known_polarity(i, local=True) != Common.DEFINITELY_ON) else: if self.known_polarity(i, local=True) != Common.DEFINITELY_ON: self.constraints.addRefConstraint( SMTLib.SMT_If( self.isOff(i), SMTLib.SMT_EQ( self.refs[i], SMTLib.SMT_IntConst( self.refSort.numInstances)), SMTLib.SMT_NE( self.refs[i], SMTLib.SMT_IntConst( self.refSort.numInstances)))) else: self.constraints.addRefConstraint( SMTLib.SMT_NE( self.refs[i], SMTLib.SMT_IntConst(self.refSort.numInstances))) #if refsort.full does not exist, create it if not self.refSort.full: self.refSort.full = lambda x: mOr(*[ SMTLib.SMT_And( SMTLib.SMT_EQ(x, SMTLib.SMT_IntConst(i)), self.refSort.isOn(i)) for i in range(self.refSort.numInstances) ]) #the clafer that the reference points to must be "on" self.constraints.addRefConstraint( SMTLib.SMT_Implies( SMTLib.SMT_NE( self.refs[i], SMTLib.SMT_IntConst(self.refSort.numInstances)), self.refSort.full(self.refs[i])))
def integerliteralVisit(self, element): if (self.inConstraint): self.currentConstraint.addArg( [IntArg(SMTLib.SMT_IntConst(element.value))])