def __init__(self,
              spec: TyrellSpec,
              interpreter: Interpreter,
              examples: List[Example],
              equal_output: Callable[[Any, Any],
                                     bool] = lambda x, y: x == y):
     super().__init__(interpreter, examples, equal_output)
     self._assert_handler = AssertionViolationHandler(spec, interpreter)
Example #2
0
 def __init__(self,
              spec: TyrellSpec,
              interpreter: Interpreter,
              examples: List[Example],
              prune: str,
              equal_output: Callable[[Any, Any],
                                     bool] = lambda x, y: x == y):
     super().__init__(interpreter, examples, equal_output)
     self._assert_handler = AssertionViolationHandler(spec, interpreter)
     self.prune = prune
     # the memory used for storing abstract evaluation result, so that we don't have to run the prune again and again
     self.abstract_eval_memory = {}
Example #3
0
class BidirectionalDecider(ExampleDecider):
    assert_handler: AssertionViolationHandler

    def __init__(self,
                 spec: TyrellSpec,
                 interpreter: Interpreter,
                 examples: List[Example],
                 prune: str,
                 equal_output: Callable[[Any, Any],
                                        bool] = lambda x, y: x == y):
        super().__init__(interpreter, examples, equal_output)
        self._assert_handler = AssertionViolationHandler(spec, interpreter)
        self.prune = prune
        # the memory used for storing abstract evaluation result, so that we don't have to run the prune again and again
        self.abstract_eval_memory = {}

    def analyze_interpreter_error(self, error: InterpreterError):
        return self._assert_handler.handle_interpreter_error(error)

    def analyze(self, prog):
        blame_finder = BlameFinder(self.interpreter, prog)
        res = blame_finder.process_examples(self.examples, self.equal_output,
                                            self.prune,
                                            self.abstract_eval_memory)
        return res
    def test_blame(self):
        enode0 = builder.make_enum('SmallInt', '-3')
        enode1 = builder.make_enum('SmallInt', '-2')
        snode = builder.make_apply('sqrt', [enode0])
        inode = builder.make_apply('id', [snode])

        interp = FooInterpreter()
        handler = AssertionViolationHandler(spec, interp)

        with self.assertRaises(AssertionViolation) as cm:
            interp.eval(inode, [])
        type_error = cm.exception
        blames = handler.handle_interpreter_error(type_error)
        self.assertIsNotNone(blames)
        self.assertEqual(len(blames), 2)
        for blame in blames:
            self.assertNotIn(Blame(inode, inode.production), blame)
            self.assertIn(Blame(snode, snode.production), blame)
            self.assertTrue((Blame(enode0, enode0.production) in blame)
                            or (Blame(enode0, enode1.production) in blame))
    def test_blame_with_capture(self):
        enode0 = builder.make_enum('SmallInt', '-2')
        cnode = builder.make_apply('const', [enode0])
        enode1 = builder.make_enum('SmallInt', '-3')
        enode2 = builder.make_enum('SmallInt', '3')
        dnode = builder.make_apply('idiv', [cnode, enode1])

        interp = FooInterpreter()
        handler = AssertionViolationHandler(spec, interp)

        with self.assertRaises(AssertionViolation) as cm:
            interp.eval(dnode, [])
        type_error = cm.exception
        blames = handler.handle_interpreter_error(type_error)
        self.assertIsNotNone(blames)
        self.assertEqual(len(blames), 2)
        for blame in blames:
            self.assertIn(Blame(dnode, dnode.production), blame)
            self.assertTrue((Blame(enode1, enode1.production) in blame)
                            or (Blame(enode1, enode2.production) in blame))
            # These nodes are captured in our assertion
            self.assertIn(Blame(cnode, cnode.production), blame)
            self.assertIn(Blame(enode0, enode0.production), blame)
class ExampleConstraintPruningDecider(ExampleDecider):
    assert_handler: AssertionViolationHandler

    def __init__(self,
                 spec: TyrellSpec,
                 interpreter: Interpreter,
                 examples: List[Example],
                 equal_output: Callable[[Any, Any],
                                        bool] = lambda x, y: x == y):
        super().__init__(interpreter, examples, equal_output)
        self._assert_handler = AssertionViolationHandler(spec, interpreter)

    def analyze_interpreter_error(self, error: InterpreterError):
        return self._assert_handler.handle_interpreter_error(error)

    def analyze(self, prog):
        blame_finder = BlameFinder(self.interpreter, prog)
        return blame_finder.process_examples(self.examples, self.equal_output)
class ExampleConstraintDecider(ExampleDecider):
    _imply_map: ImplyMap
    _assert_handler: AssertionViolationHandler

    def __init__(self,
                 spec: TyrellSpec,
                 interpreter: Interpreter,
                 examples: List[Example],
                 equal_output: Callable[[Any, Any],
                                        bool] = lambda x, y: x == y):
        super().__init__(interpreter, examples, equal_output)
        self._imply_map = self._build_imply_map(spec)
        self._assert_handler = AssertionViolationHandler(spec, interpreter)

    def _check_implies(self, pre, post) -> bool:
        def encode_property(prop_expr: PropertyExpr):
            param_expr = cast(ParamExpr, prop_expr.operand)
            var_name = '{}_p{}'.format(prop_expr.name, param_expr.index)
            ptype = prop_expr.type
            if ptype is ExprType.INT:
                return z3.Int(var_name)
            elif ptype is ExprType.BOOL:
                return z3.Bool(var_name)
            else:
                raise RuntimeError('Unrecognized ExprType: {}'.format(ptype))

        constraint_visitor = ConstraintEncoder(encode_property)

        z3_solver = z3.Solver()
        z3_pre = constraint_visitor.visit(pre)
        z3_post = constraint_visitor.visit(post)
        z3_solver.add(z3.Not(z3.Implies(z3_pre, z3_post)))
        return z3_solver.check() == z3.unsat

    def _build_imply_map(self, spec: TyrellSpec) -> ImplyMap:
        ret: MutableImplyMap = defaultdict(list)
        constrained_prods = filter(
            lambda prod: prod.is_function() and len(prod.constraints) > 0,
            spec.productions())
        for prod0, prod1 in permutations(constrained_prods, r=2):
            if len(prod0.rhs) != len(prod1.rhs):
                continue
            for c0 in prod0.constraints:
                for c1 in prod1.constraints:
                    if self._check_implies(c1, c0):
                        ret[(prod0, c0)].append(prod1)
                        break
        return ret

    def analyze(self, prog):
        '''
        This version of analyze() tries to analyze the reason why a synthesized program fails, if it does not pass all the tests.
        '''
        failed_examples = self.get_failed_examples(prog)
        if len(failed_examples) == 0:
            return ok()
        else:
            blame_finder = BlameFinder(self.interpreter, self._imply_map, prog)
            blame_finder.process_examples(failed_examples)
            blames = blame_finder.get_blames()
            if len(blames) == 0:
                return bad()
            else:
                return bad(why=blames)

    def analyze_interpreter_error(self, error: InterpreterError):
        return self._assert_handler.handle_interpreter_error(error)