def test_hardtanh(self): """ This test is a mild sanity check; don't take too seriously """ y = z3.RealVector("y", 2) x = z3.RealVector("x", 2) constraints = lantern.encode_hardtanh(x, y) s = z3.SolverFor("QF_LRA") s.add(constraints) # x_0 = -2 => y_0 = -1 s.add(x[0] == -2) s.add(x[1] == y[0]) self.assertTrue(s.check() == z3.sat) # should fail, since y_1 is constrained to -1 s.add(y[1] == 0) self.assertTrue(s.check() == z3.unsat)
def scalability_Z3(numberOfBoolVars, numOfRealVars, constraints, max_sensors_under_attack): print '\n=======================================================' print ' TEST Z3' print ' #Real Varabiles = ', numOfRealVars print ' #Bool Varabiles = ', numberOfBoolVars print ' #Bool Constraints = ', len(constraints) print '=======================================================\n' SMTsolver = z3.Solver() bVars = z3.BoolVector('b', numberOfBoolVars) rVars = z3.RealVector('y', numOfRealVars) #---------------------------------------------------------------------------- print '--> Z3: FEEDING CONSTRAINTS' #---------------------------------------------------------------------------- for constraint in constraints: boolConstraint = constraint['bool'] convexConstraint = constraint['convex'] firstVar = boolConstraint[0] Q = convexConstraint['Q'] b = convexConstraint['b'] c = convexConstraint['c'] quadConstraint = 0 for counter1 in range(0, numOfRealVars): for counter2 in range(0, numOfRealVars): quadConstraint = quadConstraint + rVars[counter1] * rVars[ counter2] * Q[counter1, counter2] linearConstraint = 0 for counter1 in range(0, numOfRealVars): linearConstraint = linearConstraint + rVars[counter1] * c[counter1] #quadConstraint = sum([i * j for i,j in zip(rVars,A)] + [-1*b[0]]) SMTsolver.add( z3.Implies(bVars[firstVar], quadConstraint + linearConstraint < b)) SMTsolver.add( sum([BoolVar2Int(bVars[i]) for i in range(0, numberOfBoolVars)]) == max_sensors_under_attack) #---------------------------------------------------------------------------- print '--> Z3: SEARCHING FOR A SOLUTION' #---------------------------------------------------------------------------- SMTsolver.set("timeout", TIMEOUTE_LIMIT * 1000) start = timeit.default_timer() SMTsolver.check() end = timeit.default_timer() time_smt_SMT = end - start print('Z3 time = ', time_smt_SMT) return time_smt_SMT
def scalability_Z3(numberOfBoolVars, numOfRealVars, constraints): print '\n=======================================================' print ' TEST Z3' print ' #Real Varabiles = ', numOfRealVars print ' #Bool Varabiles = ', numberOfBoolVars print ' #Bool Constraints = ', len(constraints) print '=======================================================\n' SMTsolver = z3.Solver() bVars = z3.BoolVector('b', numberOfBoolVars) rVars = z3.RealVector('y', numOfRealVars) #---------------------------------------------------------------------------- print '--> Z3: FEEDING CONSTRAINTS' #---------------------------------------------------------------------------- for constraint in constraints: boolConstraint = constraint['bool'] positiveVars = [abs(i) - 1 for i in boolConstraint if i > 0] negativeVars = [abs(i) - 1 for i in boolConstraint if i < 0] Z3Constraint = [bVars[i] for i in positiveVars ] + [NOT(bVars[i]) for i in negativeVars] SMTsolver.add(z3.Or(*Z3Constraint)) convexConstraint = constraint['convex'] if convexConstraint is not None: firstVar = abs(boolConstraint[-1]) - 1 A = convexConstraint['A'] b = convexConstraint['b'] linConst = sum([i * j for i, j in zip(rVars, A)] + [-1 * b[0]]) SMTsolver.add(z3.Implies(bVars[firstVar], linConst < 0)) #---------------------------------------------------------------------------- print '--> Z3: SEARCHING FOR A SOLUTION' #---------------------------------------------------------------------------- SMTsolver.set("timeout", TIMEOUTE_LIMIT * 1000) start = timeit.default_timer() SMTsolver.check() end = timeit.default_timer() time_smt_SMT = end - start print('Z3 time = ', time_smt_SMT) return time_smt_SMT
def stability_search1(phi, xsys, m): """ Attempts to find a max-affine Lyapunov function that proves global stability of an AMN: Dynamical system: x(t+1) = phi(x(t)) Lyapunov function: V(x) = max(Ax+b), A (m-by-n) and b (m) A and b are recalculated again at every E-solve step x should be a ref to the input variable to phi """ n = phi.outdim assert n == xsys.outdim assert m >= 1 # 0. Initialize print 'Initializing stability_search1' MAX_ITER = 50 # init counterexample set Xc = list() #Xc.append(np.ones((n,))) # go around the Linf 1-ball for xcpoint in itertools.product([-1, 1], repeat=n): Xc.append(np.array(xcpoint)) # init SMT solver esolver = z3.SolverFor('QF_LRA') fsolver = z3.SolverFor('QF_LRA') enc = amnet.smt.SmtEncoder(phi, solver=fsolver) enc.init_tree() print enc for iter in range(MAX_ITER): # 1. E-solve esolver.push() Avar = [z3.RealVector('A' + str(i), n) for i in range(m)] bvar = z3.RealVector('b', m) print 'iter=%s: Xc=%s' % (iter, Xc) print 'Avar=%s' % Avar print 'bvar=%s' % bvar esolver.add(_maxN_z3(bvar) == 0) for k, xk in enumerate(Xc): # point value xk_next = phi.eval(xk) # Lyapunov max expressions Vk_terms = [ z3.Sum([Avar[i][j] * xk[j] for j in range(n)]) + bvar[i] for i in range(m) ] Vk_next_terms = [ z3.Sum([Avar[i][j] * xk_next[j] for j in range(n)]) + bvar[i] for i in range(m) ] Vk_expr = _maxN_z3(Vk_terms) Vk_next_expr = _maxN_z3(Vk_next_terms) # Lyapunov function constraints for counterexample xk Vk = z3.Real('v' + str(k)) Vk_next = z3.Real('v' + str(k) + '_next') esolver.add(Vk == Vk_expr) esolver.add(Vk_next == Vk_next_expr) # nonnegativity/decrement of V if all(xk == 0): esolver.add(Vk == 0) else: # CONDITIONING: impose minimum decay rate esolver.add(Vk > 0) esolver.add(Vk_next > 0) esolver.add(Vk_next < 0.99 * Vk) # CONDITIONING: impose upper bound on b esolver.add(_normL1_z3(bvar) <= 10) esolver.add(_maxN_z3(bvar) == 0) #esolver.add([bvar[i] == 0 for i in range(m)]) # CONDITIONING: impose normalization on A for i in range(m): esolver.add(_normL1_z3(Avar[i]) <= 10) if _DEBUG_SMT2: filename = 'log/esolver_%s.smt2' % iter file = open(filename, 'w') print 'Writing %s...' % filename, file.write('(set-logic QF_LRA)\n') file.write(esolver.to_smt2()) file.write('(get-model)') print 'done!' file.close() # find a candidate Lyapunov function if esolver.check() == z3.sat: print 'iter=%s: Found new Lyapunov Function' % iter #print 'esolver=%s' % esolver model = esolver.model() A_cand = np.array([[mfp(model, Avar[i][j]) for j in range(n)] for i in range(m)]) b_cand = np.array([mfp(model, bvar[i]) for i in range(m)]) print "V(x)=max(Ax+b):" print "A=" + str(A_cand) print "b=" + str(b_cand) else: print 'iter=%s: Stability unknown, exiting' % iter esolver.pop() return None esolver.pop() # 2. F-solve # find counterexample for candidate Lyapunov function fsolver.push() # z3 symbol for input to phi x = enc.get_symbol(xsys) # encode Vx Vx_terms = [ z3.Sum([A_cand[i][j] * x[j] for j in range(n)]) + b_cand[i] for i in range(m) ] Vx_expr = _maxN_z3(Vx_terms) Vx = z3.Real('vx') fsolver.add(Vx == Vx_expr) # z3 symbol for phi(x) x_next = enc.get_symbol(phi) # encode Vx_next Vx_next_terms = [ z3.Sum([A_cand[i][j] * x_next[j] for j in range(n)]) + b_cand[i] for i in range(m) ] Vx_next_expr = _maxN_z3(Vx_next_terms) Vx_next = z3.Real('vx_next') fsolver.add(Vx_next == Vx_next_expr) # encode failure to decrement fsolver.add(z3.Not(x == 0)) fsolver.add(z3.Not(z3.And(Vx > 0, Vx_next - Vx < 0))) # CONDITIONING: only care about small counterexamples fsolver.add(_normL1_z3(x) <= 5) fsolver.add(_normL1_z3(x) >= 0.5) if _DEBUG_SMT2: filename = 'log/fsolver_%s.smt2' % iter file = open(filename, 'w') print 'Writing %s...' % filename, file.write('(set-logic QF_LRA)\n') file.write(fsolver.to_smt2()) file.write('(get-model)\n') print 'done!' file.close() # look for a counterexample if fsolver.check() == z3.sat: print 'iter=%s: Found new Counterexample' % iter #print 'fsolver=%s' % fsolver fmodel = fsolver.model() xc = np.array([mfp(fmodel, x[j]) for j in range(n)]) Xc.append(xc) else: print 'iter=%s: No Counterexample found' % iter print 'Lyapunov function found' print "V(x)=max(Ax+b):" print "A=" + str(A_cand) print "b=" + str(b_cand) fsolver.pop() return (A_cand, b_cand) fsolver.pop() # max iterations reached print 'Max iterations reached' return None
return [z3.BitVec(name + "__" + str(i), bitsCount) for i in range(count)] def generateFiniteLenFloats(name, count, tp, ctx): tp = np.dtype(tp) fpSort = floatTypes[tp.itemsize] if isinstance(fpSort, tuple): fpSort = z3.FPSort(*fpSort) return [z3.FP(name + "__" + str(i), fpSort) for i in range(count)] typesRemapping = { np.bool_: lambda name, count, tp, ctx: z3.BoolVector(name, count, ctx), bool: lambda name, count, tp, ctx: z3.BoolVector(name, count, ctx), int: lambda name, count, tp, ctx: z3.IntVector(name, count, ctx), float: lambda name, count, tp, ctx: z3.RealVector(name, count, ctx), } floatTypes = { 1: (4, 4), #2: (5, 11), 2: z3.FloatHalf(), #4: (8, 24), 4: z3.FloatSingle(), #8: (11, 53), 8: z3.FloatDouble(), 10: (15, 63), #16: (15, 111), 16: z3.FloatQuadruple(), 32: (19, 237), }
def _init_vars(self): assert self.ctx.is_valid() assert self.ctx.only_one_input() for name, phi in self.ctx.symbols.items(): self.vars[name] = z3.RealVector(prefix=name, sz=phi.outdim)
def RealVector(self, s_str, length): return z3.RealVector(s_str, length)