Coverage for moptipy / algorithms / mo / morls.py: 100%
30 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-24 08:49 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-24 08:49 +0000
1"""
2A multi-objective version of the Randomized Local Search algorithm.
4The original randomized local search (RLS) always remembers the best-so-far
5solution and, in each step, generates a new one by applying the unary search
6operator. If the new solution is not worse than the best-so-far one (according
7to the single objective function), it becomes the new best-so-far solution.
8In this multi-objective version, we accept the new solution if it is not
9dominated by the best-so-far solution.
10"""
11from typing import Callable, Final
13from numpy.random import Generator
15from moptipy.api.algorithm import Algorithm1
16from moptipy.api.mo_algorithm import MOAlgorithm
17from moptipy.api.mo_process import MOProcess
18from moptipy.api.operators import Op0, Op1
21class MORLS(Algorithm1, MOAlgorithm):
22 """The MO-RLS is a local search accepting all non-worsening moves."""
24 def solve_mo(self, process: MOProcess) -> None:
25 """
26 Apply the MO-RLS to an optimization problem.
28 :param process: the black-box process object
29 """
30 # Create records for old and new point in the search space.
31 best_x = process.create() # record for best-so-far solution
32 best_f = process.f_create() # the objective values
33 new_x = process.create() # record for new solution
34 new_f = process.f_create() # the objective values
35 # Obtain the random number generator.
36 random: Final[Generator] = process.get_random()
38 # Put function references in variables to save time.
39 evaluate: Final[Callable] = process.f_evaluate # the objective
40 op1: Final[Callable] = self.op1.op1 # the unary operator
41 should_terminate: Final[Callable] = process.should_terminate
42 domination: Final[Callable] = process.f_dominates
44 # Start at a random point in the search space and evaluate it.
45 self.op0.op0(random, best_x) # Create 1 solution randomly and
46 evaluate(best_x, best_f) # evaluate it.
48 while not should_terminate(): # Until we need to quit...
49 op1(random, new_x, best_x) # new_x = neighbor of best_x
50 evaluate(new_x, new_f)
51 if domination(new_f, best_f) <= 0: # new is not worse than best?
52 best_f, new_f = new_f, best_f # swap objective values.
53 best_x, new_x = new_x, best_x # swap best and new.
55 process.check_in(best_x, best_f) # check-in final result
57 def __init__(self, op0: Op0, op1: Op1) -> None:
58 """
59 Create the randomized local search (rls).
61 :param op0: the nullary search operator
62 :param op1: the unary search operator
63 """
64 Algorithm1.__init__(self, "morls", op0, op1)
66 def initialize(self) -> None:
67 """Initialize the algorithm."""
68 Algorithm1.initialize(self)