Pulp Solver and Numba

I’m trying to run this optimization function using @jit

def optimize(
            self,
            n: int,
            max_exposure: Optional[float] = None,
            randomness: bool = False,
            with_injured: bool = False,
            exposure_strategy: Type[BaseExposureStrategy] = TotalExposureStrategy,
    ) -> Generator[Lineup, None, None]:
        players = [player for player in self.players if player.max_exposure is None or player.max_exposure > 0]
        context = OptimizationContext(
            total_lineups=n,
            players=players,
            max_exposure=max_exposure,
            randomness=randomness,
            with_injured=with_injured,
            exposure_strategy=exposure_strategy,
        )
        rules = self._rules.copy()
        rules.update(self.settings.extra_rules)
        if randomness:
            rules.add(RandomObjective)
        else:
            rules.add(NormalObjective)
        if with_injured:
            rules.remove(RemoveInjuredRule)
        base_solver = self._solver_class()
        base_solver.setup_solver()
        players_dict = OrderedDict(
            [(player, base_solver.add_variable('Player_%d' % i)) for i, player in enumerate(players)])
        variables_dict = {v: k for k, v in players_dict.items()}
        constraints = [constraint(self, players_dict, context) for constraint in rules]
        for constraint in constraints:
            constraint.apply(base_solver)
        previous_lineup = None
        for _ in range(n):
            solver = base_solver.copy()  # type: Solver
            for constraint in constraints:
                constraint.apply_for_iteration(solver, previous_lineup)
            try:
                solved_variables = solver.solve()
                lineup_players = []
                variables_names = []
                for solved_variable in solved_variables:
                    player = variables_dict.get(solved_variable)
                    if player:
                        lineup_players.append(player)
                    variables_names.append(solved_variable.name)
                lineup = self._build_lineup(lineup_players, context)
                previous_lineup = lineup
                context.add_lineup(lineup)
                yield lineup
                if self.total_players and len(self.locked_players) == self.total_players:
                    return
                for constraint in constraints:
                    constraint.post_optimize(variables_names)
            except SolverInfeasibleSolutionException as solver_exception:
                raise GenerateLineupException(solver_exception.get_user_defined_constraints())
        self.last_context = context

but I get the error

numba.errors.UnsupportedError: Failed in nopython mode pipeline (step: analyzing bytecode)
Exception object cannot be stored into variable (solver_exception)

It says that numba partially handle exceptions, but I don’t think it handles the pulp exception is there a workaround for this issue?

hi @austinjohnson , Numba will not handle anything that it hasn’t been explicit told how to handle.

It can handle many Python built-ins (but not all, Supported Python features — Numba 0.52.0-py3.7-linux-x86_64.egg documentation), and it can handle a lot of Numpy (but not all, Supported NumPy features — Numba 0.52.0-py3.7-linux-x86_64.egg documentation). For everything else, the default is “not supported”.

Your code sample includes things like OptimizationContext which looks like something that likely Numba does not handle. Unless its a jitted function or jitclass that you built with Numba itself. Numba cannot use arbitrary classes from any library, only from those that were built with Numba.

Another way to look at it is that the njit decorator does not propagate from your function into the objects that your function calls. You need to njit from the bottom up; it’s not possible to jit from the top down. If you jit function calls something that is not itself jitted, the call with fail.

I hope this helps,

Luk