def formula(self, p): ptyp = type(p) if ptyp is BD.GTZ or ptyp is BD.GEZ or ptyp is BD.EQZ: aform = self.affine(p.expr) if ptyp is BD.GTZ: return SMT.GT(aform, SMT.Int(0)) elif ptyp is BD.GEZ: return SMT.GE(aform, SMT.Int(0)) elif ptyp is BD.EQZ: return SMT.Equals(aform, SMT.Int(0)) else: assert False elif ptyp is BD.Rel: rsym = self._ctxt.get(p.name) assert rsym is not None, f"expected relation name '{p.name}'" args = [] for a in p.args: sym = self._ctxt.get(a) assert sym is not None, f"expected variable name '{a}'" args.append(sym) return SMT.Function(rsym, args) elif ptyp is BD.Conj or ptyp is BD.Disj: lhs = self.formula(p.lhs) rhs = self.formula(p.rhs) smtop = SMT.And if ptyp is BD.Conj else SMT.Or return smtop(lhs, rhs)
def _test_to_smt(self, operator): operator = operator.to_canonical() # FIXME Integer rounding only applicable if x >= 0 def to_symbol(s): return smt.Symbol(s, typename=smt.types.INT) import math items = [smt.Times(smt.Int(int(math.floor(v))), to_symbol(k)) for k, v in operator.lhs.items()] lhs = smt.Plus([smt.Int(0)] + items) rhs = smt.Int(int(math.floor(operator.rhs))) assert operator.symbol == "<=" return smt.LE(lhs, rhs)
def affine(self, a): """ return some positive rescaling of the affine expression s.t. the rescaled expression has integer coefficients safe, since positive rescaling preserves all of a >= 0, a > 0, and a == 0 """ # find the lcm of the offset denominator # and all coefficient denominators mult = a.offset.denominator for t in a.terms: mult = _lcm(mult, t.coeff.denominator) # now, we can produce an integral affine equation, # by rescaling through with `mult` a = a * Fraction(mult) # Finally, convert this to an SMT formula assert a.offset.denominator == 1 f = SMT.Int(a.offset.numerator) for t in a.terms: assert t.coeff.denominator == 1 sym = self._ctxt.get(t.var) assert sym is not None, f"expected variable name '{t.var}'" term = SMT.Times(SMT.Int(t.coeff.numerator), sym) f = SMT.Plus(f, term) return f
def _exp_to_smt(self, expression): if isinstance(expression, sympy.Add): return smt.Plus([self._exp_to_smt(arg) for arg in expression.args]) elif isinstance(expression, sympy.Mul): return smt.Times(*[self._exp_to_smt(arg) for arg in expression.args]) elif isinstance(expression, sympy.Symbol): return smt.Symbol(str(expression), INT) try: expression = int(expression) return smt.Int(expression) except ValueError: pass raise RuntimeError("Could not parse {} of type {}".format(expression, type(expression)))
def __encodeTerminal(symbolicExpression, type): if isinstance(symbolicExpression, sympy.Symbol): if type.literal == 'Integer': return pysmt.Symbol(symbolicExpression.name, pysmt.INT) elif type.literal == 'Real': return pysmt.Symbol(symbolicExpression.name, pysmt.REAL) elif type.literal == 'Bool': return pysmt.Symbol(symbolicExpression.name, pysmt.BOOL) else: # type.literal == 'BitVector' return pysmt.Symbol(symbolicExpression.name, pysmt.BVType(type.size)) else: if type.literal == 'Integer': return pysmt.Int(symbolicExpression.p) elif type.literal == 'Real': if isinstance(symbolicExpression, sympy.Rational): return pysmt.Real(symbolicExpression.p / symbolicExpression.q) else: # isinstance(symbolicExpression, sympy.Float) return pysmt.Real(symbolicExpression) elif type.literal == 'Bool': return pysmt.Bool(symbolicExpression) else: # type.literal == 'BitVector' return pysmt.BV(symbolicExpression, type.size)
variables = [] cap = 5 # add a_i, b_i, c_i variables for each equation for n in range(1, cap + 1): variables.append(SMT.Symbol("a" + str(n), INT)) variables.append(SMT.Symbol("b" + str(n), INT)) variables.append(SMT.Symbol("c" + str(n), INT)) print(variables) constraints = [] for var in variables: string = var.__repr__() # add requirement that all a_i, c_i > -1 if string[0] == "a" or string[0] == "c": constraints.append(SMT.GT(var, SMT.Int(-1))) # add requirement that b_i > 0 else: constraints.append(SMT.GT(var, SMT.Int(0))) for i in range(0, 3 * cap, 3): # add requirement that either a_i =0 or c_i = 0 constraints.append( SMT.Or(SMT.Equals(variables[i], SMT.Int(0)), SMT.Equals(variables[i + 2], SMT.Int(0)))) # add requirement that if a_i = 0 and c_i = 0 then b_i = 1 constraints.append( SMT.Or( SMT.Or(SMT.GT(variables[i], SMT.Int(0)), SMT.GT(variables[i + 2], SMT.Int(0))), SMT.Equals(variables[i + 1], SMT.Int(1))))
def __getExpressionTree(symbolicExpression): # TODO LATER: take into account bitwise shift operations args = [] castType = None if len(symbolicExpression.args) > 0: for symbolicArg in symbolicExpression.args: arg, type = Solver.__getExpressionTree(symbolicArg) args.append(arg) if castType is None: castType = type else: if castType.literal == 'Integer': if type.literal == 'Real': castType = type # TODO LATER: consider other possible castings if castType.literal == 'Real': for i in range(len(args)): args[i] = pysmt.ToReal(args[i]) if isinstance(symbolicExpression, sympy.Not): if castType.literal == 'Integer': return pysmt.Equals(args[0], pysmt.Int(0)), Type('Bool') elif castType.literal == 'Real': return pysmt.Equals(args[0], pysmt.Real(0)), Type('Bool') elif castType.literal == 'Bool': return pysmt.Not(args[0]), Type('Bool') else: # castType.literal == 'BitVector' return pysmt.BVNot(args[0]), Type('BitVector') elif isinstance(symbolicExpression, sympy.Lt): return pysmt.LT(args[0], args[1]), Type('Bool') elif isinstance(symbolicExpression, sympy.Gt): return pysmt.GT(args[0], args[1]), Type('Bool') elif isinstance(symbolicExpression, sympy.Ge): return pysmt.GE(args[0], args[1]), Type('Bool') elif isinstance(symbolicExpression, sympy.Le): return pysmt.LE(args[0], args[1]), Type('Bool') elif isinstance(symbolicExpression, sympy.Eq): return pysmt.Equals(args[0], args[1]), Type('Bool') elif isinstance(symbolicExpression, sympy.Ne): return pysmt.NotEquals(args[0], args[1]), Type('Bool') elif isinstance(symbolicExpression, sympy.And): if castType.literal == 'Bool': return pysmt.And(args[0], args[1]), Type('Bool') else: # type.literal == 'BitVector' return pysmt.BVAnd(args[0], args[1]), castType elif isinstance(symbolicExpression, sympy.Or): if castType.literal == 'Bool': return pysmt.Or(args[0], args[1]), Type('Bool') else: # type.literal == 'BitVector' return pysmt.BVOr(args[0], args[1]), castType elif isinstance(symbolicExpression, sympy.Xor): return pysmt.BVXor(args[0], args[1]), castType elif isinstance(symbolicExpression, sympy.Add): return pysmt.Plus(args), castType elif isinstance(symbolicExpression, sympy.Mul): return pysmt.Times(args), castType elif isinstance(symbolicExpression, sympy.Pow): return pysmt.Pow(args[0], args[1]), castType # TODO LATER: deal with missing modulo operator from pysmt else: if isinstance(symbolicExpression, sympy.Symbol): symbolType = Variable.symbolTypes[symbolicExpression.name] literal = symbolType.getTypeForSolver() designator = symbolType.designatorExpr1 type = Type(literal, designator) return Solver.__encodeTerminal(symbolicExpression, type), type elif isinstance(symbolicExpression, sympy.Integer): type = Type('Integer') return Solver.__encodeTerminal(symbolicExpression, type), type elif isinstance(symbolicExpression, sympy.Rational): type = Type('Real') return Solver.__encodeTerminal(symbolicExpression, type), type elif isinstance(symbolicExpression, sympy.Float): type = Type('Real') return Solver.__encodeTerminal(symbolicExpression, type), type else: type = Type('Real') return Solver.__encodeTerminal(symbolicExpression, type), type