Beispiel #1
0
    def iter_specs(self,
                   inp_spec: EngineSpec,
                   depth: int,
                   programs: List[Set[FunctionCall]] = None):
        """
        The basic version evaluates all argument combinations, and maintains a cache
        of results which clubs together combinations that produce the same result.
        This cache is then iterated over at the end to produce the new specs for the next
        depth level. If this is the last function in the overall sequence, then the values
        are returned along with programs as final results.

        The checking of the result against the output is NOT done here. This will be the responsibility
        of the function-sequence engine. This is to afford the capability of pausing/restarting
        this argument engine.
        """
        func: BaseGenerator = self.func_sequence[depth - 1]
        if programs is None:
            programs = [None] * len(self.func_sequence)

        result_cache: ResultCache = ResultCache()
        for arg_vals, arg_annotations in self.iter_args_wrapper(
                inp_spec, depth, programs):
            result = self.execute(func, arg_vals, arg_annotations)
            if self.stats is not None:
                self.stats.num_cands_generated[depth] += 1

            if result is None:
                if self.stats is not None:
                    self.stats.num_cands_error[depth] += 1

                continue

            call: FunctionCall = FunctionCall(func, arg_vals, arg_annotations)
            result_cache.insert(result, call)

        if depth == len(self.func_sequence):
            for result, calls in result_cache.iter_results():
                programs[depth - 1] = calls
                if self.stats is not None:
                    self.stats.num_cands_propagated[depth] += 1

                yield result, programs
                programs[depth - 1] = None

        else:
            for result, calls in result_cache.iter_results():
                programs[depth - 1] = calls
                inp_spec.intermediates[depth - 1] = result
                inp_spec.depth = depth + 1
                if self.stats is not None:
                    self.stats.num_cands_propagated[depth] += 1

                yield from self.iter_specs(inp_spec, depth + 1, programs)
                programs[depth - 1] = None

            inp_spec.depth = depth
Beispiel #2
0
    def iter_specs(self,
                   inp_spec: EngineSpec,
                   depth: int,
                   programs: List[Set[FunctionCall]] = None):
        """
        The checking of the result against the output is NOT done here. This will be the responsibility
        of the function-sequence engine. This is to afford the capability of pausing/restarting
        this argument engine.
        """
        func: BaseGenerator = self.func_sequence[depth - 1]
        if programs is None:
            programs = [None] * len(self.func_sequence)

        for arg_vals, arg_annotations, prob in self.iter_args_wrapper(
                inp_spec, depth, programs):
            result = self.execute(func, arg_vals, arg_annotations)
            if self.stats is not None:
                self.stats.num_cands_generated[depth] += 1

            if result is None:
                if self.stats is not None:
                    self.stats.num_cands_error[depth] += 1

                continue

            call: FunctionCall = FunctionCall(func, arg_vals, arg_annotations)

            if depth == len(self.func_sequence):
                programs[depth - 1] = [call]
                if self.stats is not None:
                    self.stats.num_cands_propagated[depth] += 1

                if self.get_probs:
                    yield result, programs, prob
                else:
                    yield result, programs

                programs[depth - 1] = None

            else:
                programs[depth - 1] = [call]
                inp_spec.intermediates[depth - 1] = result
                inp_spec.depth = depth + 1
                if self.stats is not None:
                    self.stats.num_cands_propagated[depth] += 1

                yield from self.iter_specs(inp_spec, depth + 1, programs)
                programs[depth - 1] = None
                inp_spec.intermediates[depth - 1] = None

                inp_spec.depth = depth
Beispiel #3
0
    def search(self) -> bool:
        """
        This method dictates how the sequences are processed.
        The basic version here either processes a sequence fully or permanently discard it
        """

        target_output = self.iospec.output
        checker = Checker.get_checker(target_output)
        self.solutions = []

        for func_seq in self.iter_func_seqs():
            if self.stats is not None:
                self.stats.num_seqs_explored += 1

            self.engine_spec = EngineSpec(self.iospec.inputs, self.iospec.output, max_depth=len(func_seq))
            arg_engine = self.get_arg_engine(func_seq)
            for result, programs in arg_engine.run(self.engine_spec):
                if checker(target_output, result):
                    self.report_solution(programs)
                    if self.stop_first_solution:
                        return True

            arg_engine.close()

        return len(self.solutions) > 0