def get_synthesizer(): code = """a = HOLE""" vars = contract.ProgramVars({'x': 'Int', 'y': 'Int'}, {'a': 'Int'}) code_pre = 'x >= 1 and y >= 1' code_post = 'a == 6*x + y' sygus_grammar = """ ( ( Start Int ( ( Constant Int ) x y (+ Start Start) (* ( Constant Int ) Start) ) ) ) """ #(- Start Start) grammar = templates.load_gramar_from_SYGUS_spec(sygus_grammar) hole = smt_synthesis.HoleDecl('HOLE', grammar, { 'x': 'Int', 'y': 'Int' }, is_expression_hole=True, max_depth=3) env = utils.Options({ '--solver': 'z3', '--logic': 'NIA', '--produce_proofs': True, '--silent': True }) return smt_synthesis.SynthesizerSMT(code, code_pre, code_post, vars, env, [hole])
def test_program_already_in_ssa_form(self): code = 'x = 0; y = 1; z = 2' post = 'z < 2' vars = contract.ProgramVars({'x': 'Int', 'y': 'Int'}, {'z': 'Int'}) # Running SSA conversion ib = ast_utils.py_to_interm_ib(code) post = ast_utils.py_to_interm_expr(post) ib2, post2 = ssa_converter.convert(ib, post, vars) vars.add_marked_variables(ib2.src.collect_variables()) # Assertions self.assertFalse(ib.src.equals(ib2.src)) # ----------------------------------- self.assertEquals("|x'|", ib2.src.instructions[0].var.id) self.assertEquals("|y'|", ib2.src.instructions[1].var.id) self.assertEquals("z", ib2.src.instructions[2].var.id) self.assertEquals(3, ib2.src.size()) self.assertEquals("z", post2.src.expr.args[0].id) ib2, post2 = ssa_converter.convert(ib2, post2, vars) self.assertFalse(ib.src.equals(ib2)) # ----------------------------------- self.assertEquals("|x'|", ib2.src.instructions[0].var.id) self.assertEquals("|y'|", ib2.src.instructions[1].var.id) self.assertEquals("z", ib2.src.instructions[2].var.id) self.assertEquals(3, ib2.src.size()) self.assertEquals("z", post2.src.expr.args[0].id)
def test_4(): code = """ res = x if x < 0: HOLE return res """ input_vars = contract.ProgramVars({'x': 'Int', 'res': 'Double'}) pre = 'True' post = 'res >= 0' pysv.smt_synthesis.synthesize(code, pre, post, input_vars)
def test_ssa_form_holes(self): code = """ trigger = False newAcc = acc + 2 newAcc = newAcc - 1 if newAcc < limit: trigger = False else: newAcc = HOLE # should be 0 newAcc = newAcc - 1 trigger = True """ post = 'True' vars = contract.ProgramVars({ 'acc': 'Int', 'limit': 'Int' }, { 'newAcc': 'Int', 'trigger': 'Bool' }) grammar_spec = """ ( ( Start Int ( ( Constant Int ) acc limit newAcc) ) ) """ from pysv import templates grammar = templates.load_gramar_from_SYGUS_spec(grammar_spec) hole = smt_synthesis.HoleDecl('HOLE', grammar, None, True) ib = ast_utils.py_to_interm_ib(code, [hole]) holes = ib.src.get_holes_definitions() self.assertEquals(1, len(holes)) self.assertEquals({ 'acc': 'Int', 'limit': 'Int', 'newAcc': 'Int' }, holes[0].vars) post = ast_utils.py_to_interm_expr(post) ib2, post2 = ssa_converter.convert(ib, post, vars) holes = ib2.src.get_holes_definitions() self.assertEquals(1, len(holes)) self.assertEquals({ 'acc': 'Int', 'limit': 'Int', "|newAcc'|": 'Int' }, holes[0].vars)
def test_verify_smt2_simple_program(self): prog = "(= res (ite (= x 5) -1 1))" pre = "true" post = "(> res 0)" program_vars = contract.ProgramVars({'x': 'Int'}, {'res': 'Int'}) env = utils.Options(["--lang", "smt2"]) res = smt_verifier.verify(prog, pre, post, program_vars, env) self.assertEquals('sat', res.decision) self.assertEquals('5', res.model['x']) self.assertEquals({'x': '5'}, res.witness) post = "(>= res -1)" res = smt_verifier.verify(prog, pre, post, program_vars, env) self.assertEquals('unsat', res.decision) self.assertEquals({}, res.model) self.assertEquals({}, res.witness)
def test_verify_smt2_minimize(self): prog = "true" pre = "true" post = "(and (< res 0) (<= res 0) (= res 0) (= res 0))" program_vars = contract.ProgramVars({'res': 'Int'}, {}) env = utils.Options([ "--lang", "smt2", "--ver_mode", "min", "--post_in_cnf", 1, "--ver_annotate_post", 1, "--logic", "LIA", "--produce_assignments", 1 ]) res = smt_verifier.verify(prog, pre, post, program_vars, env) self.assertEquals('sat', res.decision) self.assertEquals(True, int(res.model['res']) > 0) self.assertEquals('false', res.assignments['post_0']) self.assertEquals('false', res.assignments['post_1']) self.assertEquals('false', res.assignments['post_2']) self.assertEquals('false', res.assignments['post_3'])
def test_6(): """Testing the synthesis of a Python program.""" code = """ trigger = False newAcc = acc + 1 if newAcc < limit: trigger = False else: newAcc = HOLE # should be 0 newAcc = newAcc - 1 trigger = True """ vars = contract.ProgramVars({ 'acc': 'Int', 'limit': 'Int' }, { 'newAcc': 'Int', 'trigger': 'Bool' }) code_pre = 'acc < limit and acc >= 0 and limit > 0' t1 = (['acc == limit - 1'], ['trigger == True', 'newAcc == 0']) t2 = (['acc < limit - 1'], ['trigger == False', 'newAcc == acc + 1']) code_post = contract.formula_test_cases_py([t1, t2]) grammar_spec = """ ( ( Start Int ( ( Constant Int ) acc limit newAcc) ) ) """ import pysv.templates grammar = pysv.templates.load_gramar_from_SYGUS_spec(grammar_spec) hole = pysv.smt_synthesis.HoleDecl('HOLE', grammar, vars.input_vars, True) holes_defs = {hole.id: hole} res = pysv.smt_synthesis.synthesize(code, code_pre, code_post, vars, holes_defs) # Printing result print('******** Z3 RESULT ********\n' + str(res)) if res.decision == 'sat': print("MODEL FOUND!") elif res.decision == 'unsat': print("MODEL NOT FOUND!")
def test_simple_program_no_ifs(self): code = 'x=0; y=1; z=2; x=3; y=4' post = 'x<2 and z<2' vars = contract.ProgramVars({'x': 'Int', 'y': 'Int', 'z': 'Int'}) # Running SSA conversion ib = ast_utils.py_to_interm_ib(code) post = ast_utils.py_to_interm_expr(post) ib2, post2 = ssa_converter.convert(ib, post, vars) # Assertions self.assertEquals("|x'|", ib2.src.instructions[0].var.id) self.assertEquals("|y'|", ib2.src.instructions[1].var.id) self.assertEquals("|z'|", ib2.src.instructions[2].var.id) self.assertEquals("|x''|", ib2.src.instructions[3].var.id) self.assertEquals("|y''|", ib2.src.instructions[4].var.id) self.assertEquals(5, ib2.src.size()) self.assertEquals("|x''|", post2.src.expr.args[0].args[0].id) self.assertEquals("|z'|", post2.src.expr.args[1].args[0].id)
def synthesize_max(): code = """ if H1: res = H2 else: res = H3 """ code_pre = 'True' code_post = 'res >= x and res >= y and (res == x or res == y)' # Specification of the hole's template in the form of the grammar in SYGUS format. sygus_grammar_hole1 = """ ( ( Start Bool ( (Constant Bool) (> TermInt TermInt) (>= TermInt TermInt) (= TermInt TermInt) (<= TermInt TermInt) (< TermInt TermInt) ) ) ( TermInt Int ( (Constant Int) x y ) ) ) """ sygus_grammar_hole23 = """ ( ( Start Int ( (Constant Int) x y (+ x y) (- x y) (- y x) (+ x ( Constant Int )) (+ y ( Constant Int )) ) ) ) """ grammar1 = templates.load_gramar_from_SYGUS_spec(sygus_grammar_hole1) grammar23 = templates.load_gramar_from_SYGUS_spec(sygus_grammar_hole23) pv = contract.ProgramVars({'x': 'Int', 'y': 'Int'}, {'res': 'Int'}) h1 = smt_synthesis.HoleDecl('H1', grammar1, pv, True, 2) h2 = smt_synthesis.HoleDecl('H2', grammar23, pv, True, 2) h3 = smt_synthesis.HoleDecl('H3', grammar23, pv, True, 2) hole_decls = [h1, h2, h3] # The result is currently only a raw output from the solver, but one can verify from the model # that synthesized program is correct. env = utils.Options(['--solver', 'z3', '--logic', 'NIA']) res = smt_synthesis.synthesize(code, code_pre, code_post, pv, env, hole_decls) return res
def test_7(): """Testing the synthesis of a Python program.""" code = """ a = HOLE if x != 5: a = a + 1 else: a = a - 1 """ vars = contract.ProgramVars({'x': 'Int', 'y': 'Int'}, {'a': 'Int'}) code_pre = 'x >= 1 and y >= 1' code_post = 'a == 6*x + y' grammar_spec = """ ( ( Start Int ( ( Constant Int ) x y (+ Start Start) (* ( Constant Int ) Start) ) ) ) """ import pysv.templates grammar = pysv.templates.load_gramar_from_SYGUS_spec(grammar_spec) hole = pysv.smt_synthesis.HoleDecl('HOLE', grammar, { 'x': 'Int', 'y': 'Int' }, True, max_depth=3) holes_defs = {hole.id: hole} res = pysv.smt_synthesis.synthesize(code, code_pre, code_post, vars, holes_defs) # Printing result print('******** Z3 RESULT ********') print(res.text) print('--------------------------\n') print('SYNTHESIZED PYTHON CODE:') print(res.final_code)
def synthesize_keijzer12(): smtgp_nia_grammar = """ ( ( Start Int ( x y (Constant Int) (+ Start Start) (- Start Start) (* Start Start) (div Start Start) (ite SBool Start Start) ) ) ( SBool Bool ( (> Start Start) (>= Start Start) (< Start Start) (<= Start Start) (= Start Start) (= SBool SBool) ) ) ) """ vars = contract.ProgramVars({'x': 'Int', 'y': 'Int'}, {'res': 'Int'}) code = """(= res H1)""" code_pre = 'true' code_post = 'true' grammar = templates.load_gramar_from_SYGUS_spec(smtgp_nia_grammar) h1 = smt_synthesis.HoleDecl('H1', grammar, {'x': 'Int', 'y': 'Int'}, True, 6) hole_decls = [h1] tc = contract.TestCases.from_csv(csv_keijzer12) env = utils.Options(['--solver', 'z3', '--logic', 'NIA', "--lang", "smt2"]) res = smt_synthesis.synthesize_tc(tc, code, code_pre, code_post, vars, env, hole_decls) return res
def test_5(): """Testing the generation of SMT-LIB script and solving it with z3. """ code = """ z = 6 if (y > 4): y = x * (x + y) else: z = 6 """ input_vars = contract.ProgramVars({'x': 'Int', 'y': 'Int', 'z': 'Int'}) code_pre = 'x >= 2 and y > 2' code_post = 'y > x and y < z' # Converting source code into internal code representation ib, pre, post = pysv.smt_verifier.process_source_code( code, code_pre, code_post) ib, post = pysv.ssa_converter.convert(ib, pre, post, input_vars) # Specifying variables and their types input_vars.add_marked_variables(ib.collect_variables()) print('VARIABLES: ' + str(input_vars)) # Producing SMT-LIB script smtlib = SMTLIBConstraints(show_comments=False) script = smtlib.produce_script_verification(ib, pre, post, input_vars) print('\n\n******** SCRIPT ********:\n' + script) # Solving constraints solverZ3 = SolverZ3() res = solverZ3.apply(script) # Printing result print('******** Z3 RESULT ********\n' + str(res)) if res.decision == 'sat': print("MODEL FOUND!") elif res.decision == 'unsat': print("MODEL NOT FOUND!")
if res.decision == 'unsat': print('Counterexample not found! Program is correct.') elif res.decision == 'sat': print(res.witness) print('Counterexample found! Program is incorrect.') print('----------------------------------------------\n\n') return res #------------------------------------------------------------------------ # MAIN #------------------------------------------------------------------------ precondition = 'True' postcondition = "res >= x and res >= y and (res == x or res == y)" variables = contract.ProgramVars({'x': 'Int', 'y': 'Int'}, {'res': 'Int'}) # First, we will verify incorrect implementation of the program. Notice that a counterexample is returned. code =\ """ if x < y: res = x else: res = y """ verify_code(code, precondition, postcondition, variables) # After previous verification we analyzed the code and slightly changed condition in the IF statement. # The code should now be correct, but just to be sure we run verifier yet again. code =\ """
# Only one leap zune_simplified = """ #year = 1980 #if days > 365: # handled by precondition days2 = days year2 = year if year % 4 == 0: if days > 366: days2 = days - 366 year2 = year + 1 # lack of else statement else: days2 = days - 365 year2 = year + 1 """ input_vars = contract.ProgramVars({"days": 'Int', "year": 'Int'}) pre = "days > 365 and year >= 1980" # For this postcondition program doesn't meet the specification because the postcondition # is based on user intent and cod has a bug. # post = "((not days == 366 or not year == 1980) or (year2 == 1980 and days2 == 0)) and " +\ # "((not days == 366 or not year == 1981) or (year2 == 1982 and days2 == 1))" # For this postcondition program meets the specification because the postcondition # is based on the code. #post = "((not days == 366 or not year == 1980) or (year2 == 1980 and days2 == 366)) and " +\ # "((not days == 366 or not year == 1981) or (year2 == 1982 and days2 == 1))" t1 = (["days == 366", "year == 1980"], ["year2 == 1980", "days2 == 366"]) t2 = (["days == 366", "year == 1981"], ["year2 == 1982", "days2 == 1"]) post = contract.formula_test_cases_py([t1, t2]) days = 9
def test_simple_program_one_if(self): code = """ x = 0 y = 0 if x<2: x = 1 x = x + 1 else: x = 3 y = 2 x = x + 5 """ post = 'x<2 and y<2' vars = contract.ProgramVars({'x': 'Int'}, {'y': 'Int'}) # Running SSA conversion ib = ast_utils.py_to_interm_ib(code) post = ast_utils.py_to_interm_expr(post) ib2, post2 = ssa_converter.convert(ib, post, vars) # Assertions self.assertEquals("|x'|", ib2.src.instructions[0].var.id) self.assertEquals("y", ib2.src.instructions[1].var.id) if_instr = ib2.src.instructions[2] self.assertEquals("<(|x'|, 2)", str(if_instr.condition)) # BODY branch self.assertEquals("|x''| = 1", str(if_instr.body[0])) self.assertEquals("|x''|", if_instr.body[0].var.id) self.assertEquals(False, if_instr.body[0].is_meta) self.assertEquals("|x'''| = +(|x''|, 1)", str(if_instr.body[1])) self.assertEquals("|x'''|", if_instr.body[1].var.id) self.assertEquals(False, if_instr.body[1].is_meta) # meta self.assertEquals("|x'''''| = |x'''| (meta)", str(if_instr.body[2])) self.assertEquals("|x'''''|", if_instr.body[2].var.id) self.assertEquals("|x'''|", if_instr.body[2].expr.id) self.assertEquals(True, if_instr.body[2].is_meta) self.assertEquals("|y''| = y (meta)", str(if_instr.body[3])) self.assertEquals("|y''|", if_instr.body[3].var.id) self.assertEquals("y", if_instr.body[3].expr.id) self.assertEquals(True, if_instr.body[3].is_meta) # ORELSE branch self.assertEquals("|x''''| = 3", str(if_instr.orelse[0])) self.assertEquals("|x''''|", if_instr.orelse[0].var.id) self.assertEquals(False, if_instr.orelse[0].is_meta) self.assertEquals("|y'| = 2", str(if_instr.orelse[1])) self.assertEquals("|y'|", if_instr.orelse[1].var.id) self.assertEquals(False, if_instr.orelse[1].is_meta) # meta self.assertEquals("|x'''''| = |x''''| (meta)", str(if_instr.orelse[2])) self.assertEquals("|x'''''|", if_instr.orelse[2].var.id) self.assertEquals("|x''''|", if_instr.orelse[2].expr.id) self.assertEquals(True, if_instr.orelse[2].is_meta) self.assertEquals("|y''| = |y'| (meta)", str(if_instr.orelse[3])) self.assertEquals("|y''|", if_instr.orelse[3].var.id) self.assertEquals("|y'|", if_instr.orelse[3].expr.id) self.assertEquals(True, if_instr.orelse[3].is_meta) # After if self.assertEquals("|x''''''|", ib2.src.instructions[3].var.id) self.assertEquals("|x'''''|", ib2.src.instructions[3].expr.args[0].id) # Postcondition self.assertEquals("|x''''''|", post2.src.expr.args[0].args[0].id) self.assertEquals("|y''|", post2.src.expr.args[1].args[0].id)
def get_program_vars(env): in_vars = {vt.split(":")[0]: vt.split(":")[1] for vt in env.input_vars} loc_vars = {vt.split(":")[0]: vt.split(":")[1] for vt in env.local_vars} return contract.ProgramVars(in_vars, loc_vars)
True, max_depth=4) return [h1] if __name__ == "__main__": if len(sys.argv) == 1 or "-h" in sys.argv or "--help" in sys.argv: print("Usage: ./get_final_code.py [raw output from SMT solver]") exit() result = sys.argv[1] # Original source code (fixed for this prettifier instance). original_code = get_original_code() # Hole declarations (fixed for this prettifier instance). holes_decls = get_hole_declarations( contract.ProgramVars(input_vars={ "x": "Int", "y": "Int", "z": "Int" })) # Options (fixed for this prettifier instance). env = utils.Options(merge_with_vargs=False) res = smt_synthesis.SynthesisResult(result, original_code, holes_decls, env) print("FINAL CODE:") print(res.final_code)
# # I think that this is a very convenient compromise between full formal contracts and test cases as # we know from GP. t1 = (['acc == limit - 1'], ['trigger == True', 'newAcc == 0']) t2 = (['acc < limit - 1'], ['trigger == False', 'newAcc == acc + 1']) postcondition = contract.formula_test_cases_py([t1, t2]) # We must also specify types of variables used in the program, because dynamic typing in Python # does not allow us to reliably obtain this information via reflection. In Scala this could be # automatically generated from the source code. variables = contract.ProgramVars({ 'acc': 'Int', 'limit': 'Int' }, { 'newAcc': 'Int', 'trigger': 'Bool' }) # First, we will verify incorrect implementation of the modulo counter. If user invokes this program # for example with 'acc' equal to 2 and 'limit' equal to 3, then counter modulo three will return 3, # which is incorrect. # # As can be seen, verifier without any problems discovers an example of incorrect behavior. code =\ """ trigger = False if acc < limit: newAcc = acc + 1 else: