N-Wouda / ALNS

Adaptive large neighbourhood search (and more!) in Python.
https://alns.readthedocs.io/en/latest/
MIT License
448 stars 124 forks source link

Generalize on_best to on_outcome #94

Closed leonlan closed 2 years ago

leonlan commented 2 years ago

ALNS currently supports a callback function to be called when ALNS finds a new global best solution state:

https://github.com/N-Wouda/ALNS/blob/55e5cfc8b77609b825512e4622478f48f1102183/alns/ALNS.py#L254-L267

Since we use the notion of outcomes in ALNS, we can generalize this hook to work for other outcomes such as better, accepted, and rejected as well.

A simple proposal is to replace on_best with a new method:

def on_best(self, func: _OperatorType, outcome: Outcome):
     self._on_outcome[outcome] = func

I am not aware of any papers that do this. Maybe it's just a redundant addition.

N-Wouda commented 2 years ago

I think that makes sense. To not break the current code, I think we should consider an addition:


def on_best(self, func):
    self.on_outcome(func, Outcome.BEST)

def on_outcome(self, func, outcome):
    self._on_outcome[outcome] = func
N-Wouda commented 2 years ago

Since the actual amount of code needed for this is very small, we could also just do on_best, on_better, on_accept, on_reject as explicit methods, rather than expose the Outcome enum to the users.

N-Wouda commented 2 years ago

This comment is relevant here:

Should we create an IntEnum for the evaluation outcome, and pass that to update, rather than a meaningless integer s_idx?

I'm thinking of

import enum

class Outcome(enum.IntEnum):
    BEST = 0
    BETTER = 1
    ACCEPTED = 2
    REJECTED = 3

Originally posted by @N-Wouda in https://github.com/N-Wouda/ALNS/issues/74#issuecomment-1300368691

N-Wouda commented 2 years ago

This one's pretty easy as well. I will try to finish this one tonight, so we can submit our JOSS paper (#58). @leonlan could you review the resulting PR?