diff --git a/src/mlrose_ky/__init__.py b/src/mlrose_ky/__init__.py index bed2fab7..bdf93ca4 100644 --- a/src/mlrose_ky/__init__.py +++ b/src/mlrose_ky/__init__.py @@ -25,26 +25,15 @@ from .algorithms.decay import GeomDecay, ArithDecay, ExpDecay, CustomSchedule # noinspection PyUnresolvedReferences -from .algorithms.crossovers import OnePointCrossover, UniformCrossover, TSPCrossover +from .algorithms.crossovers import OnePointCrossOver, UniformCrossOver, TSPCrossOver # noinspection PyUnresolvedReferences from .algorithms.mutators import ChangeOneMutator, DiscreteMutator, SwapMutator, ShiftOneMutator # noinspection PyUnresolvedReferences -from .fitness import ( - OneMax, - FlipFlop, - FourPeaks, - SixPeaks, - ContinuousPeaks, - Knapsack, - TravellingSales, - Queens, - MaxKColor, - CustomFitness, -) +from .fitness import OneMax, FlipFlop, FourPeaks, SixPeaks, ContinuousPeaks, Knapsack, TravellingSales, Queens, MaxKColor, CustomFitness -# noinspection PyUnresolvedReferences +# noinspection PyUnresolvedReferences,PyProtectedMember from .neural import NeuralNetwork, LinearRegression, LogisticRegression, NNClassifier, _nn_core # noinspection PyUnresolvedReferences diff --git a/src/mlrose_ky/algorithms/__init__.py b/src/mlrose_ky/algorithms/__init__.py index 0923ccb8..ced6237b 100644 --- a/src/mlrose_ky/algorithms/__init__.py +++ b/src/mlrose_ky/algorithms/__init__.py @@ -3,12 +3,15 @@ # Authors: Genevieve Hayes (modified by Andrew Rollings, Kyle Nakamura) # License: BSD 3-clause -from .crossovers import UniformCrossover, TSPCrossover, OnePointCrossover -from .decay import ArithDecay, CustomSchedule, ExpDecay, GeomDecay from .ga import genetic_alg from .gd import gradient_descent from .hc import hill_climb from .mimic import mimic -from .mutators import ChangeOneMutator, DiscreteMutator, ShiftOneMutator, SwapMutator from .rhc import random_hill_climb from .sa import simulated_annealing + +from .crossovers import UniformCrossOver, TSPCrossOver, OnePointCrossOver + +from .decay import ArithDecay, CustomSchedule, ExpDecay, GeomDecay + +from .mutators import ChangeOneMutator, DiscreteMutator, ShiftOneMutator, SwapMutator diff --git a/src/mlrose_ky/algorithms/crossovers/__init__.py b/src/mlrose_ky/algorithms/crossovers/__init__.py index 63b3e28d..4a19eeb5 100644 --- a/src/mlrose_ky/algorithms/crossovers/__init__.py +++ b/src/mlrose_ky/algorithms/crossovers/__init__.py @@ -3,6 +3,6 @@ # Author: Genevieve Hayes # License: BSD 3-clause -from .one_point_crossover import OnePointCrossover -from .tsp_crossover import TSPCrossover -from .uniform_crossover import UniformCrossover +from .one_point_crossover import OnePointCrossOver +from .tsp_crossover import TSPCrossOver +from .uniform_crossover import UniformCrossOver diff --git a/src/mlrose_ky/algorithms/crossovers/_crossover_base.py b/src/mlrose_ky/algorithms/crossovers/_crossover_base.py index 5ea36553..19064fd5 100644 --- a/src/mlrose_ky/algorithms/crossovers/_crossover_base.py +++ b/src/mlrose_ky/algorithms/crossovers/_crossover_base.py @@ -8,10 +8,12 @@ # License: BSD 3-clause from abc import ABC, abstractmethod -from typing import Any +from typing import Any, Sequence +import numpy as np -class _CrossoverBase(ABC): + +class _CrossOverBase(ABC): """ Base class for crossover operations in a genetic algorithm. @@ -20,7 +22,7 @@ class _CrossoverBase(ABC): Parameters ---------- - optimization_problem : Any + opt_prob : Any An instance of the optimization problem related to the genetic algorithm. This problem instance should provide necessary properties like 'length' that might be needed for the crossover operation. @@ -34,21 +36,21 @@ class _CrossoverBase(ABC): 'length' property. """ - def __init__(self, optimization_problem: Any): + def __init__(self, opt_prob: Any): """ - Initialize the CrossoverBase with the given optimization problem. + Initialize the _CrossOverBase with the given optimization problem. Parameters ---------- - optimization_problem : Any + opt_prob : Any An instance of the optimization problem related to the GA. """ super().__init__() - self._opt_prob: Any = optimization_problem - self._length: int = optimization_problem.length + self._opt_prob: Any = opt_prob + self._length: int = opt_prob.length @abstractmethod - def mate(self, parent1: Any, parent2: Any) -> Any: + def mate(self, p1: Sequence[int | float], p2: Sequence[int | float]) -> np.ndarray: """ Perform the crossover (mating) between two parents to produce offspring. @@ -57,14 +59,14 @@ def mate(self, parent1: Any, parent2: Any) -> Any: Parameters ---------- - parent1 : Any + p1 : Sequence[int | float] The first parent participating in the crossover. - parent2 : Any + p2 : Sequence[int | float] The second parent participating in the crossover. Returns ------- - Any + np.ndarray The offspring resulting from the crossover. The type of this result can vary depending on the specific GA implementation. """ diff --git a/src/mlrose_ky/algorithms/crossovers/one_point_crossover.py b/src/mlrose_ky/algorithms/crossovers/one_point_crossover.py index ab498edf..4a7b787c 100644 --- a/src/mlrose_ky/algorithms/crossovers/one_point_crossover.py +++ b/src/mlrose_ky/algorithms/crossovers/one_point_crossover.py @@ -11,10 +11,10 @@ import numpy as np -from mlrose_ky.algorithms.crossovers._crossover_base import _CrossoverBase +from mlrose_ky.algorithms.crossovers._crossover_base import _CrossOverBase -class OnePointCrossover(_CrossoverBase): +class OnePointCrossOver(_CrossOverBase): """ One-point crossover for genetic algorithms. @@ -23,21 +23,21 @@ class OnePointCrossover(_CrossoverBase): is exchanged to create a new offspring. Inherits from: - _CrossoverBase : Abstract base class for crossover operations. + _CrossOverBase : Abstract base class for crossover operations. """ - def __init__(self, optimization_problem: Any): + def __init__(self, opt_prob: Any): """ - Initialize the OnePointCrossover with the given optimization problem. + Initialize the OnePointCrossOver with the given optimization problem. Parameters ---------- - optimization_problem : Any + opt_prob : Any An instance of the optimization problem related to the genetic algorithm. """ - super().__init__(optimization_problem) + super().__init__(opt_prob) - def mate(self, parent1: Sequence[float], parent2: Sequence[float]) -> np.ndarray: + def mate(self, p1: Sequence[float], p2: Sequence[float]) -> np.ndarray: """ Perform the one-point crossover between two parent sequences to produce offspring. @@ -46,9 +46,9 @@ def mate(self, parent1: Sequence[float], parent2: Sequence[float]) -> np.ndarray Parameters ---------- - parent1 : Sequence[float] + p1 : Sequence[float] The first parent chromosome sequence. - parent2 : Sequence[float] + p2 : Sequence[float] The second parent chromosome sequence. Returns @@ -57,4 +57,4 @@ def mate(self, parent1: Sequence[float], parent2: Sequence[float]) -> np.ndarray The offspring chromosome resulting from the crossover. """ crossover_point = 1 + np.random.randint(self._length - 1) - return np.array([*parent1[:crossover_point], *parent2[crossover_point:]]) + return np.array([*p1[:crossover_point], *p2[crossover_point:]]) diff --git a/src/mlrose_ky/algorithms/crossovers/tsp_crossover.py b/src/mlrose_ky/algorithms/crossovers/tsp_crossover.py index e29b9c5f..4cb5126e 100644 --- a/src/mlrose_ky/algorithms/crossovers/tsp_crossover.py +++ b/src/mlrose_ky/algorithms/crossovers/tsp_crossover.py @@ -12,10 +12,10 @@ import numpy as np -from mlrose_ky.algorithms.crossovers._crossover_base import _CrossoverBase +from mlrose_ky.algorithms.crossovers._crossover_base import _CrossOverBase -class TSPCrossover(_CrossoverBase): +class TSPCrossOver(_CrossOverBase): """ Crossover operation tailored for the Travelling Salesperson Problem (TSP) in genetic algorithms. @@ -24,21 +24,21 @@ class TSPCrossover(_CrossoverBase): logic to combine parental genes. Inherits from: - _CrossoverBase : Abstract base class for crossover operations. + _CrossOverBase : Abstract base class for crossover operations. """ - def __init__(self, optimization_problem: Any): + def __init__(self, opt_prob: Any): """ - Initialize the TSPCrossover with the given optimization problem. + Initialize the TSPCrossOver with the given optimization problem. Parameters ---------- - optimization_problem : Any + opt_prob : Any An instance of the optimization problem related to the genetic algorithm. """ - super().__init__(optimization_problem) + super().__init__(opt_prob) - def mate(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.ndarray: + def mate(self, p1: Sequence[int], p2: Sequence[int]) -> np.ndarray: """ Perform the crossover (mating) between two parent sequences to produce offspring. @@ -47,9 +47,9 @@ def mate(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.ndarray: Parameters ---------- - parent1 : Sequence[int] + p1 : Sequence[int] The first parent representing a TSP route. - parent2 : Sequence[int] + p2 : Sequence[int] The second parent representing a TSP route. Returns @@ -57,18 +57,18 @@ def mate(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.ndarray: np.ndarray The offspring representing a new TSP route. """ - return self._mate_fill(parent1, parent2) + return self._mate_fill(p1, p2) - def _mate_fill(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.ndarray: + def _mate_fill(self, p1: Sequence[int], p2: Sequence[int]) -> np.ndarray: """ Perform a fill-based crossover using a segment of the first parent and filling the rest with non-repeated cities from the second parent. Parameters ---------- - parent1 : Sequence[int] + p1 : Sequence[int] The first parent representing a TSP route. - parent2 : Sequence[int] + p2 : Sequence[int] The second parent representing a TSP route. Returns @@ -79,15 +79,15 @@ def _mate_fill(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.ndarr if self._length > 1: n = 1 + np.random.randint(self._length - 1) child = np.array([0] * self._length) - child[:n] = parent1[:n] - unvisited = [city for city in parent2 if city not in parent1[:n]] + child[:n] = p1[:n] + unvisited = [city for city in p2 if city not in p1[:n]] child[n:] = unvisited else: - child = np.copy(parent1 if np.random.randint(2) == 0 else parent2) + child = np.copy(p1 if np.random.randint(2) == 0 else p2) return child - def _mate_traverse(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.ndarray: + def _mate_traverse(self, parent_1: Sequence[int], parent_2: Sequence[int]) -> np.ndarray: """ Perform a traversal-based crossover using city adjacency considerations from both parents to construct a viable TSP route. @@ -98,9 +98,9 @@ def _mate_traverse(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.n Parameters ---------- - parent1 : Sequence[int] + parent_1 : Sequence[int] The first parent representing a TSP route. - parent2 : Sequence[int] + parent_2 : Sequence[int] The second parent representing a TSP route. Returns @@ -109,13 +109,13 @@ def _mate_traverse(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.n The offspring TSP route. """ if self._length > 1: - next_city_parent1 = np.append(parent1[1:], parent1[0]) - next_city_parent2 = np.append(parent2[1:], parent2[0]) + next_city_parent1 = np.append(parent_1[1:], parent_1[0]) + next_city_parent2 = np.append(parent_2[1:], parent_2[0]) visited_cities = [False] * self._length offspring_route = np.array([0] * self._length) - starting_city = np.random.randint(len(parent1)) + starting_city = np.random.randint(len(parent_1)) offspring_route[0] = starting_city visited_cities[starting_city] = True @@ -137,13 +137,13 @@ def _mate_traverse(self, parent1: Sequence[int], parent2: Sequence[int]) -> np.n next_city = next_city2 if fitness1 > fitness2 else next_city1 # Choose the smaller distance else: while True: - next_city = np.random.randint(len(parent1)) + next_city = np.random.randint(len(parent_1)) if not visited_cities[next_city]: break offspring_route[index] = next_city visited_cities[next_city] = True else: - offspring_route = np.copy(parent1 if np.random.randint(2) == 0 else parent2) + offspring_route = np.copy(parent_1 if np.random.randint(2) == 0 else parent_2) return offspring_route diff --git a/src/mlrose_ky/algorithms/crossovers/uniform_crossover.py b/src/mlrose_ky/algorithms/crossovers/uniform_crossover.py index 5c7f247e..6da597a3 100644 --- a/src/mlrose_ky/algorithms/crossovers/uniform_crossover.py +++ b/src/mlrose_ky/algorithms/crossovers/uniform_crossover.py @@ -12,10 +12,10 @@ import numpy as np -from mlrose_ky.algorithms.crossovers._crossover_base import _CrossoverBase +from mlrose_ky.algorithms.crossovers._crossover_base import _CrossOverBase -class UniformCrossover(_CrossoverBase): +class UniformCrossOver(_CrossOverBase): """ Uniform crossover for genetic algorithms. @@ -24,21 +24,21 @@ class UniformCrossover(_CrossoverBase): method is often used when no prior knowledge about the problem structure is known. Inherits from: - _CrossoverBase : Abstract base class for crossover operations. + _CrossOverBase : Abstract base class for crossover operations. """ - def __init__(self, optimization_problem: Any): + def __init__(self, opt_prob: Any): """ - Initialize the UniformCrossover with the given optimization problem. + Initialize the UniformCrossOver with the given optimization problem. Parameters ---------- - optimization_problem : Any + opt_prob : Any An instance of the optimization problem related to the genetic algorithm. """ - super().__init__(optimization_problem) + super().__init__(opt_prob) - def mate(self, parent1: Sequence[float], parent2: Sequence[float]) -> np.ndarray: + def mate(self, p1: Sequence[float], p2: Sequence[float]) -> np.ndarray: """ Perform the uniform crossover between two parent sequences to produce offspring. @@ -47,9 +47,9 @@ def mate(self, parent1: Sequence[float], parent2: Sequence[float]) -> np.ndarray Parameters ---------- - parent1 : Sequence[float] + p1 : Sequence[float] The first parent chromosome sequence. - parent2 : Sequence[float] + p2 : Sequence[float] The second parent chromosome sequence. Returns @@ -58,5 +58,5 @@ def mate(self, parent1: Sequence[float], parent2: Sequence[float]) -> np.ndarray The offspring chromosome resulting from the crossover. """ gene_selector = np.random.randint(2, size=self._length) - stacked_parents = np.vstack((parent1, parent2)) + stacked_parents = np.vstack((p1, p2)) return stacked_parents[gene_selector, np.arange(self._length)] diff --git a/src/mlrose_ky/algorithms/decay/__init__.py b/src/mlrose_ky/algorithms/decay/__init__.py index 32ab6dbe..bcb149b4 100644 --- a/src/mlrose_ky/algorithms/decay/__init__.py +++ b/src/mlrose_ky/algorithms/decay/__init__.py @@ -3,7 +3,7 @@ # Author: Genevieve Hayes # License: BSD 3-clause -from .arithmetic_decay import ArithDecay -from .custom_decay import CustomSchedule -from .exponential_decay import ExpDecay -from .geometric_decay import GeomDecay +from .arith_decay import ArithDecay +from .custom_schedule import CustomSchedule +from .expl_decay import ExpDecay +from .geom_decay import GeomDecay diff --git a/src/mlrose_ky/algorithms/decay/arithmetic_decay.py b/src/mlrose_ky/algorithms/decay/arith_decay.py similarity index 93% rename from src/mlrose_ky/algorithms/decay/arithmetic_decay.py rename to src/mlrose_ky/algorithms/decay/arith_decay.py index 433fd5b8..25900bc7 100644 --- a/src/mlrose_ky/algorithms/decay/arithmetic_decay.py +++ b/src/mlrose_ky/algorithms/decay/arith_decay.py @@ -64,13 +64,13 @@ def __eq__(self, other: object) -> bool: return False return self.init_temp == other.init_temp and self.decay == other.decay and self.min_temp == other.min_temp - def evaluate(self, time: int) -> float: + def evaluate(self, t: int) -> float: """ Calculate and return the temperature parameter at the given time. Parameters ---------- - time : int + t : int The time at which to evaluate the temperature parameter. Returns @@ -78,15 +78,15 @@ def evaluate(self, time: int) -> float: float The temperature parameter at the given time, respecting the minimum temperature. """ - return max(self.init_temp - (self.decay * time), self.min_temp) + return max(self.init_temp - (self.decay * t), self.min_temp) - def get_info(self, time: int = None, prefix: str = "") -> dict: + def get_info__(self, t: int = None, prefix: str = "") -> dict: """ Generate a dictionary containing the decay schedule's settings and optionally its current value. Parameters ---------- - time : int, optional + t : int, optional The time at which to evaluate the current temperature value. If provided, the current value is included in the returned dictionary. prefix : str, optional @@ -106,7 +106,7 @@ def get_info(self, time: int = None, prefix: str = "") -> dict: f"{info_prefix}min_temp": self.min_temp, } - if time is not None: - info[f"{info_prefix}current_value"] = self.evaluate(time) + if t is not None: + info[f"{info_prefix}current_value"] = self.evaluate(t) return info diff --git a/src/mlrose_ky/algorithms/decay/custom_decay.py b/src/mlrose_ky/algorithms/decay/custom_schedule.py similarity index 100% rename from src/mlrose_ky/algorithms/decay/custom_decay.py rename to src/mlrose_ky/algorithms/decay/custom_schedule.py diff --git a/src/mlrose_ky/algorithms/decay/exponential_decay.py b/src/mlrose_ky/algorithms/decay/expl_decay.py similarity index 99% rename from src/mlrose_ky/algorithms/decay/exponential_decay.py rename to src/mlrose_ky/algorithms/decay/expl_decay.py index 0eec1db0..65f48c86 100644 --- a/src/mlrose_ky/algorithms/decay/exponential_decay.py +++ b/src/mlrose_ky/algorithms/decay/expl_decay.py @@ -6,9 +6,6 @@ import numpy as np -# temp comment - - class ExpDecay: """ Defines an exponential decay schedule for the temperature parameter T in simulated annealing, diff --git a/src/mlrose_ky/algorithms/decay/geometric_decay.py b/src/mlrose_ky/algorithms/decay/geom_decay.py similarity index 100% rename from src/mlrose_ky/algorithms/decay/geometric_decay.py rename to src/mlrose_ky/algorithms/decay/geom_decay.py diff --git a/src/mlrose_ky/algorithms/ga.py b/src/mlrose_ky/algorithms/ga.py index 3e84694b..e2f3f6fd 100644 --- a/src/mlrose_ky/algorithms/ga.py +++ b/src/mlrose_ky/algorithms/ga.py @@ -110,7 +110,7 @@ def genetic_alg( max_iters: int | float = np.inf, curve: bool = False, random_state: int = None, - state_fitness_callback: Callable[..., Any] = None, + state_fitness_callback: Callable = None, callback_user_info: Any = None, hamming_factor: float = 0.0, hamming_decay_factor: float = None, diff --git a/src/mlrose_ky/algorithms/hc.py b/src/mlrose_ky/algorithms/hc.py index 1ff8a1a7..267e2cba 100644 --- a/src/mlrose_ky/algorithms/hc.py +++ b/src/mlrose_ky/algorithms/hc.py @@ -13,7 +13,7 @@ @short_name("hc") def hill_climb( problem: Any, - max_iters: int = np.inf, + max_iters: int | float = np.inf, restarts: int = 0, init_state: np.ndarray = None, curve: bool = False, diff --git a/src/mlrose_ky/algorithms/mimic.py b/src/mlrose_ky/algorithms/mimic.py index ee8ddbf3..31b6459d 100644 --- a/src/mlrose_ky/algorithms/mimic.py +++ b/src/mlrose_ky/algorithms/mimic.py @@ -17,7 +17,7 @@ def mimic( keep_pct: float = 0.2, max_attempts: int = 10, noise: float = 0.0, - max_iters: int = np.inf, + max_iters: int | float = np.inf, curve: bool = False, random_state: int = None, state_fitness_callback: Callable = None, diff --git a/src/mlrose_ky/algorithms/mutators/__init__.py b/src/mlrose_ky/algorithms/mutators/__init__.py index e5ef3892..0bf03ef6 100644 --- a/src/mlrose_ky/algorithms/mutators/__init__.py +++ b/src/mlrose_ky/algorithms/mutators/__init__.py @@ -3,7 +3,7 @@ # Authors: Genevieve Hayes (modified by Andrew Rollings, Kyle Nakamura) # License: BSD 3-clause +from .change_one_mutator import ChangeOneMutator from .discrete_mutator import DiscreteMutator -from .gene_swap_mutator import SwapMutator -from .single_gene_mutator import ChangeOneMutator -from .single_shift_mutator import ShiftOneMutator +from .shift_one_mutator import ShiftOneMutator +from .swap_mutator import SwapMutator diff --git a/src/mlrose_ky/algorithms/mutators/_mutator_base.py b/src/mlrose_ky/algorithms/mutators/_mutator_base.py index 9b3aaeec..2e24b026 100644 --- a/src/mlrose_ky/algorithms/mutators/_mutator_base.py +++ b/src/mlrose_ky/algorithms/mutators/_mutator_base.py @@ -40,7 +40,7 @@ def __init__(self, opt_prob: Any): self._length: int = opt_prob.length @abstractmethod - def mutate(self, child: np.ndarray, mutation_probability: float) -> Any: + def mutate(self, child: np.ndarray, mutation_probability: float) -> np.ndarray: """ Apply mutation operation to a given child chromosome based on a mutation probability. diff --git a/src/mlrose_ky/algorithms/mutators/single_gene_mutator.py b/src/mlrose_ky/algorithms/mutators/change_one_mutator.py similarity index 100% rename from src/mlrose_ky/algorithms/mutators/single_gene_mutator.py rename to src/mlrose_ky/algorithms/mutators/change_one_mutator.py diff --git a/src/mlrose_ky/algorithms/mutators/single_shift_mutator.py b/src/mlrose_ky/algorithms/mutators/shift_one_mutator.py similarity index 100% rename from src/mlrose_ky/algorithms/mutators/single_shift_mutator.py rename to src/mlrose_ky/algorithms/mutators/shift_one_mutator.py diff --git a/src/mlrose_ky/algorithms/mutators/gene_swap_mutator.py b/src/mlrose_ky/algorithms/mutators/swap_mutator.py similarity index 100% rename from src/mlrose_ky/algorithms/mutators/gene_swap_mutator.py rename to src/mlrose_ky/algorithms/mutators/swap_mutator.py diff --git a/src/mlrose_ky/algorithms/rhc.py b/src/mlrose_ky/algorithms/rhc.py index 7ec54473..38f53da3 100644 --- a/src/mlrose_ky/algorithms/rhc.py +++ b/src/mlrose_ky/algorithms/rhc.py @@ -14,7 +14,7 @@ def random_hill_climb( problem: Any, max_attempts: int = 10, - max_iters: int = np.inf, + max_iters: int | float = np.inf, restarts: int = 0, init_state: np.ndarray = None, curve: bool = False, diff --git a/src/mlrose_ky/algorithms/sa.py b/src/mlrose_ky/algorithms/sa.py index 91e83667..bccd948a 100644 --- a/src/mlrose_ky/algorithms/sa.py +++ b/src/mlrose_ky/algorithms/sa.py @@ -16,7 +16,7 @@ def simulated_annealing( problem: Any, schedule: Any = GeomDecay(), max_attempts: int = 10, - max_iters: int = np.inf, + max_iters: int | float = np.inf, init_state: np.ndarray = None, curve: bool = False, random_state: int = None, diff --git a/src/mlrose_ky/decorators/short_name_decorator.py b/src/mlrose_ky/decorators/short_name_decorator.py index 1213406b..d561e39e 100644 --- a/src/mlrose_ky/decorators/short_name_decorator.py +++ b/src/mlrose_ky/decorators/short_name_decorator.py @@ -29,12 +29,12 @@ def short_name(expr: str) -> Callable: A decorator that assigns the provided short name to a function and returns the function. """ - def decorator(func: Callable) -> Callable: + def short_name_func_applicator(func: Callable) -> Callable: """Assign a short name to the given function.""" func.__short_name__ = expr return func - return decorator + return short_name_func_applicator def get_short_name(v: Any) -> str: diff --git a/src/mlrose_ky/fitness/__init__.py b/src/mlrose_ky/fitness/__init__.py index 19946004..e79e84f0 100644 --- a/src/mlrose_ky/fitness/__init__.py +++ b/src/mlrose_ky/fitness/__init__.py @@ -1,7 +1,6 @@ """Classes for defining fitness functions (i.e., optimization problems) for optimization algorithms.""" from .continuous_peaks import ContinuousPeaks -from .custom_fitness import CustomFitness from .flip_flop import FlipFlop from .four_peaks import FourPeaks from .knapsack import Knapsack @@ -9,4 +8,6 @@ from .one_max import OneMax from .queens import Queens from .six_peaks import SixPeaks -from .travelling_salesperson import TravellingSales +from .travelling_sales import TravellingSales + +from .custom_fitness import CustomFitness diff --git a/src/mlrose_ky/fitness/continuous_peaks.py b/src/mlrose_ky/fitness/continuous_peaks.py index c1eb91fc..d1275278 100644 --- a/src/mlrose_ky/fitness/continuous_peaks.py +++ b/src/mlrose_ky/fitness/continuous_peaks.py @@ -38,8 +38,8 @@ class ContinuousPeaks: """ def __init__(self, t_pct: float = 0.1): - self.t_pct: float = t_pct self.prob_type: str = "discrete" + self.t_pct: float = t_pct if not (0 <= self.t_pct <= 1): raise ValueError(f"t_pct must be between 0 and 1, got {self.t_pct} instead.") diff --git a/src/mlrose_ky/fitness/custom_fitness.py b/src/mlrose_ky/fitness/custom_fitness.py index c30b7dfb..c44850e7 100644 --- a/src/mlrose_ky/fitness/custom_fitness.py +++ b/src/mlrose_ky/fitness/custom_fitness.py @@ -59,8 +59,8 @@ def __init__(self, fitness_fn: Callable[..., float], problem_type: str = "either if problem_type not in ["discrete", "continuous", "tsp", "either"]: raise ValueError(f"Invalid problem_type: {problem_type}. Must be one of ['discrete', 'continuous', 'tsp', 'either'].") - self.fitness_fn: Callable[..., float] = fitness_fn self.problem_type: str = problem_type + self.fitness_fn: Callable[..., float] = fitness_fn self.kwargs: Any = kwargs def evaluate(self, state: np.ndarray) -> float: diff --git a/src/mlrose_ky/fitness/four_peaks.py b/src/mlrose_ky/fitness/four_peaks.py index b005cce6..86577a7b 100644 --- a/src/mlrose_ky/fitness/four_peaks.py +++ b/src/mlrose_ky/fitness/four_peaks.py @@ -58,8 +58,8 @@ def __init__(self, t_pct: float = 0.1): t_pct : float, optional, default=0.1 Threshold parameter (T) for Four Peaks fitness function. """ - self.t_pct: float = t_pct self.prob_type: str = "discrete" + self.t_pct: float = t_pct if not (0 <= self.t_pct <= 1): raise ValueError(f"threshold_pct must be between 0 and 1, got {self.t_pct}.") diff --git a/src/mlrose_ky/fitness/six_peaks.py b/src/mlrose_ky/fitness/six_peaks.py index ddf94c7f..4b9daceb 100644 --- a/src/mlrose_ky/fitness/six_peaks.py +++ b/src/mlrose_ky/fitness/six_peaks.py @@ -59,8 +59,8 @@ def __init__(self, t_pct: float = 0.1): t_pct : float, optional, default=0.1 Threshold parameter (T) for Six Peaks fitness function. """ - self.t_pct: float = t_pct self.prob_type: str = "discrete" + self.t_pct: float = t_pct if not (0 <= self.t_pct <= 1): raise ValueError(f"threshold_pct must be between 0 and 1, got {self.t_pct}.") diff --git a/src/mlrose_ky/fitness/travelling_salesperson.py b/src/mlrose_ky/fitness/travelling_sales.py similarity index 100% rename from src/mlrose_ky/fitness/travelling_salesperson.py rename to src/mlrose_ky/fitness/travelling_sales.py index 2cd0b9b8..55276087 100644 --- a/src/mlrose_ky/fitness/travelling_salesperson.py +++ b/src/mlrose_ky/fitness/travelling_sales.py @@ -89,33 +89,6 @@ def __init__(self, coords: list[tuple] = None, distances: list[tuple] = None): self.distance_matrix[u, v] = d self.distance_matrix[v, u] = d - def evaluate(self, state: np.ndarray) -> float: - """ - Evaluate the fitness of a state vector. - - Parameters - ---------- - state : np.ndarray - State array for evaluation. Each integer between 0 and (len(state) - 1), inclusive must appear exactly once in the array. - - Returns - ------- - fitness : float - Value of fitness function. Returns np.inf if travel between two consecutive nodes on the tour is not possible. - """ - # Validation checks on the state array - if self.is_coords and len(state) != len(self.coords): - raise ValueError("state must have the same length as coords.") - if not len(state) == len(set(state)): - raise ValueError("Each node must appear exactly once in state.") - if min(state) < 0: - raise ValueError("All elements of state must be non-negative integers.") - if max(state) >= len(state): - raise ValueError("All elements of state must be less than len(state).") - - # Calculate and return the fitness of the state - return float(self.calculate_fitness(state)) - def __calculate_fitness_by_coords(self, state: np.ndarray) -> float: """ Calculate fitness based on coordinates. @@ -170,6 +143,33 @@ def __calculate_fitness_by_distance(self, state: np.ndarray) -> float: return float(fitness) + def evaluate(self, state: np.ndarray) -> float: + """ + Evaluate the fitness of a state vector. + + Parameters + ---------- + state : np.ndarray + State array for evaluation. Each integer between 0 and (len(state) - 1), inclusive must appear exactly once in the array. + + Returns + ------- + fitness : float + Value of fitness function. Returns np.inf if travel between two consecutive nodes on the tour is not possible. + """ + # Validation checks on the state array + if self.is_coords and len(state) != len(self.coords): + raise ValueError("state must have the same length as coords.") + if not len(state) == len(set(state)): + raise ValueError("Each node must appear exactly once in state.") + if min(state) < 0: + raise ValueError("All elements of state must be non-negative integers.") + if max(state) >= len(state): + raise ValueError("All elements of state must be less than len(state).") + + # Calculate and return the fitness of the state + return float(self.calculate_fitness(state)) + def get_prob_type(self) -> str: """ Return the problem type. diff --git a/src/mlrose_ky/generators/knapsack_generator.py b/src/mlrose_ky/generators/knapsack_generator.py index a7c5cd85..e3caa1e1 100644 --- a/src/mlrose_ky/generators/knapsack_generator.py +++ b/src/mlrose_ky/generators/knapsack_generator.py @@ -68,8 +68,8 @@ def generate( np.random.seed(seed) - weights = 1 + np.random.randint(max_weight_per_item, size=number_of_item_types) - values = 1 + np.random.randint(max_value_per_item, size=number_of_item_types) + weights = np.random.randint(1, max_weight_per_item + 1, size=number_of_item_types).tolist() + values = np.random.randint(1, max_value_per_item + 1, size=number_of_item_types).tolist() return KnapsackOpt( length=number_of_item_types, diff --git a/src/mlrose_ky/gridsearch/grid_search_mixin.py b/src/mlrose_ky/gridsearch/grid_search_mixin.py index b05e6a65..52bc07a3 100644 --- a/src/mlrose_ky/gridsearch/grid_search_mixin.py +++ b/src/mlrose_ky/gridsearch/grid_search_mixin.py @@ -40,7 +40,7 @@ def __init__(self, scorer_method: Callable = None): self._params: inspect.Signature = inspect.signature(self._scorer_method) self._get_y_argmax: bool = False - def perform_grid_search( + def _perform_grid_search( self, classifier: Any, x_train: np.ndarray, y_train: np.ndarray, cv: int, parameters: dict, n_jobs: int = 1, verbose: bool = False ) -> skms.GridSearchCV: """ @@ -58,10 +58,10 @@ def perform_grid_search( Number of cross-validation folds. parameters : dict Dictionary with parameters names as keys and lists of parameter settings to try as values. - n_jobs : int, optional - Number of jobs to run in parallel. Defaults to 1. - verbose : bool, optional - Whether to display verbose output during grid search. Defaults to False. + n_jobs : int, optional, default=1 + Number of jobs to run in parallel. + verbose : bool, optional, default=1 + Whether to display verbose output during grid search. Returns ------- diff --git a/src/mlrose_ky/neural/__init__.py b/src/mlrose_ky/neural/__init__.py index a3b1108f..c6edf441 100644 --- a/src/mlrose_ky/neural/__init__.py +++ b/src/mlrose_ky/neural/__init__.py @@ -3,10 +3,13 @@ # Authors: Genevieve Hayes (modified by Andrew Rollings, Kyle Nakamura) # License: BSD 3-clause -from .activation import identity, relu, leaky_relu, sigmoid, softmax, tanh -from .fitness.network_weights import NetworkWeights from .linear_regression import LinearRegression from .logistic_regression import LogisticRegression from .neural_network import NeuralNetwork from .nn_classifier import NNClassifier + +from .activation import identity, relu, leaky_relu, sigmoid, softmax, tanh + +from .fitness.network_weights import NetworkWeights + from .utils import flatten_weights, unflatten_weights diff --git a/src/mlrose_ky/opt_probs/opt_prob.py b/src/mlrose_ky/opt_probs/_opt_prob.py similarity index 97% rename from src/mlrose_ky/opt_probs/opt_prob.py rename to src/mlrose_ky/opt_probs/_opt_prob.py index 550063ee..b904d036 100644 --- a/src/mlrose_ky/opt_probs/opt_prob.py +++ b/src/mlrose_ky/opt_probs/_opt_prob.py @@ -113,7 +113,7 @@ def eval_fitness(self, state: np.ndarray) -> float: self.fitness_evaluations += 1 return fitness - def eval_mate_probs(self): + def eval_mate_probs(self) -> None: """Calculate the probability of each member of the population reproducing.""" pop_fitness = np.copy(self.pop_fitness) @@ -210,7 +210,7 @@ def get_state(self) -> np.ndarray: """ return self.state - def set_population(self, new_population: np.ndarray): + def set_population(self, new_population: np.ndarray) -> None: """Set a new population and evaluate its fitness. Parameters @@ -221,11 +221,11 @@ def set_population(self, new_population: np.ndarray): self.population = new_population self.evaluate_population_fitness() - def evaluate_population_fitness(self): + def evaluate_population_fitness(self) -> None: """Evaluate the fitness of the current population.""" self.pop_fitness = np.array([self.eval_fitness(indiv) for indiv in self.population]) - def set_state(self, new_state: np.ndarray): + def set_state(self, new_state: np.ndarray) -> None: """Set a new state vector and evaluate its fitness. Parameters diff --git a/src/mlrose_ky/opt_probs/continuous_opt.py b/src/mlrose_ky/opt_probs/continuous_opt.py index f95bf0c1..6a77d4a9 100644 --- a/src/mlrose_ky/opt_probs/continuous_opt.py +++ b/src/mlrose_ky/opt_probs/continuous_opt.py @@ -4,7 +4,7 @@ import numpy as np -from mlrose_ky.opt_probs.opt_prob import _OptProb +from mlrose_ky.opt_probs._opt_prob import _OptProb # Authors: Genevieve Hayes (modified by Andrew Rollings, Kyle Nakamura) @@ -63,10 +63,10 @@ def __init__(self, length: int, fitness_fn: Any, maximize: bool = True, min_val: if (max_val - min_val) < step: raise ValueError(f"step size must be less than (max_val - min_val).") + self.prob_type: str = "continuous" self.min_val: float = min_val self.max_val: float = max_val self.step: float = step - self.prob_type: str = "continuous" def calculate_updates(self) -> list: """Calculate gradient descent updates. diff --git a/src/mlrose_ky/opt_probs/discrete_opt.py b/src/mlrose_ky/opt_probs/discrete_opt.py index 153b2362..4ffe9558 100644 --- a/src/mlrose_ky/opt_probs/discrete_opt.py +++ b/src/mlrose_ky/opt_probs/discrete_opt.py @@ -10,9 +10,9 @@ from scipy.sparse.csgraph import minimum_spanning_tree, depth_first_tree from sklearn.metrics import mutual_info_score -from mlrose_ky.algorithms.crossovers import UniformCrossover, TSPCrossover +from mlrose_ky.algorithms.crossovers import UniformCrossOver, TSPCrossOver from mlrose_ky.algorithms.mutators import SwapMutator -from mlrose_ky.opt_probs.opt_prob import _OptProb +from mlrose_ky.opt_probs._opt_prob import _OptProb class DiscreteOpt(_OptProb): @@ -34,8 +34,8 @@ class DiscreteOpt(_OptProb): Number of unique values that each element in the state vector can take. Assumes values are integers in the range 0 to (max_val - 1), inclusive. - crossover : UniformCrossover | TSPCrossover, default=None - Crossover operation used for reproduction. If None, defaults to `UniformCrossover`. + crossover : UniformCrossOver | TSPCrossOver, default=None + Crossover operation used for reproduction. If None, defaults to `UniformCrossOver`. mutator : SwapMutator, default=None Mutation operation used for reproduction. If None, defaults to `SwapMutator`. @@ -54,7 +54,7 @@ class DiscreteOpt(_OptProb): Problem type; always 'discrete' for this class. noise : float Noise factor for probability density estimation. - _crossover : UniformCrossover + _crossover : UniformCrossOver Crossover operation for reproduction. _mutator : SwapMutator Mutation operation for reproduction. @@ -70,7 +70,7 @@ def __init__( fitness_fn: Any, maximize: bool = True, max_val: int = 2, - crossover: UniformCrossover | TSPCrossover = None, + crossover: UniformCrossOver | TSPCrossOver = None, mutator: "SwapMutator" = None, ): self._get_mutual_info_impl = self._get_mutual_info_slow @@ -93,20 +93,20 @@ def __init__( else: self.max_val: int = max_val + self.prob_type: str = "discrete" self.keep_sample: np.ndarray = np.array([]) self.node_probs: np.ndarray = np.zeros([self.length, self.max_val, self.max_val]) self.parent_nodes: np.ndarray = np.array([]) self.sample_order: list[int] = [] - self.prob_type: str = "discrete" self.noise: float = 0 - self._crossover: UniformCrossover | TSPCrossover = UniformCrossover(self) if crossover is None else crossover + self._crossover: UniformCrossOver | TSPCrossOver = UniformCrossOver(self) if crossover is None else crossover self._mutator: SwapMutator = SwapMutator(self) if mutator is None else mutator self._mut_mask: np.ndarray | None = None self._mut_inf: np.ndarray | None = None - def eval_node_probs(self): + def eval_node_probs(self) -> None: """Update probability density estimates.""" mutual_info = self._get_mutual_info_impl() @@ -143,7 +143,7 @@ def eval_node_probs(self): self.node_probs = probs self.parent_nodes = parent - def set_mimic_fast_mode(self, fast_mode: bool): + def set_mimic_fast_mode(self, fast_mode: bool) -> None: """Enable or disable MIMIC fast mode.""" if fast_mode: mut_mask = np.zeros([self.length, self.length], dtype=bool) @@ -214,7 +214,7 @@ def _get_mutual_info_fast(self) -> np.ndarray: return mutual_info - def find_neighbors(self): + def find_neighbors(self) -> None: """Find all neighbors of the current state.""" self.neighbors = [] @@ -233,7 +233,7 @@ def find_neighbors(self): neighbor[i] = j self.neighbors.append(neighbor) - def find_sample_order(self): + def find_sample_order(self) -> None: """Determine order in which to generate sample vector elements.""" sample_order = [] last = [0] @@ -253,7 +253,7 @@ def find_sample_order(self): self.sample_order = sample_order - def find_top_pct(self, keep_pct: float): + def find_top_pct(self, keep_pct: float) -> None: """Select samples with fitness in the top keep_pct percentile. Parameters @@ -318,7 +318,7 @@ def random_neighbor(self) -> np.ndarray: return neighbor - def random_pop(self, pop_size: int): + def random_pop(self, pop_size: int) -> None: """Create a population of random state vectors. Parameters @@ -367,7 +367,7 @@ def reproduce(self, parent_1: np.ndarray, parent_2: np.ndarray, mutation_prob: f child = self._crossover.mate(parent_1, parent_2) return self._mutator.mutate(child, mutation_prob) - def reset(self): + def reset(self) -> None: """Set the current state vector to a random value and get its fitness.""" self.state = self.random() self.fitness = self.eval_fitness(self.state) diff --git a/src/mlrose_ky/opt_probs/flip_flop_opt.py b/src/mlrose_ky/opt_probs/flip_flop_opt.py index 1fe4a07d..bfdcbcfb 100644 --- a/src/mlrose_ky/opt_probs/flip_flop_opt.py +++ b/src/mlrose_ky/opt_probs/flip_flop_opt.py @@ -7,7 +7,7 @@ import numpy as np -from mlrose_ky.algorithms.crossovers import OnePointCrossover +from mlrose_ky.algorithms.crossovers import OnePointCrossOver from mlrose_ky.algorithms.mutators import ChangeOneMutator from mlrose_ky.fitness import FlipFlop from mlrose_ky.opt_probs.discrete_opt import DiscreteOpt @@ -27,8 +27,8 @@ class FlipFlopOpt(DiscreteOpt): maximize : bool, default=True Whether to maximize the fitness function. Set :code:`False` for minimization problems. - crossover : OnePointCrossover, default=None - Crossover operation used for reproduction. If None, defaults to `OnePointCrossover`. + crossover : OnePointCrossOver, default=None + Crossover operation used for reproduction. If None, defaults to `OnePointCrossOver`. mutator : ChangeOneMutator, default=None Mutation operation used for reproduction. If None, defaults to `ChangeOneMutator`. @@ -56,7 +56,7 @@ def __init__( length: int = None, fitness_fn: Any = None, maximize: bool = True, - crossover: "OnePointCrossover" = None, + crossover: "OnePointCrossOver" = None, mutator: "ChangeOneMutator" = None, ): if (fitness_fn is None) and (length is None): @@ -71,7 +71,7 @@ def __init__( fitness_fn = FlipFlop() self.max_val: int = 2 - crossover = OnePointCrossover(self) if crossover is None else crossover + crossover = OnePointCrossOver(self) if crossover is None else crossover mutator = ChangeOneMutator(self) if mutator is None else mutator super().__init__(length, fitness_fn, maximize, crossover=crossover, mutator=mutator) diff --git a/src/mlrose_ky/opt_probs/knapsack_opt.py b/src/mlrose_ky/opt_probs/knapsack_opt.py index 4304bfc6..3fbeecb8 100644 --- a/src/mlrose_ky/opt_probs/knapsack_opt.py +++ b/src/mlrose_ky/opt_probs/knapsack_opt.py @@ -5,7 +5,7 @@ from typing import Any -from mlrose_ky.algorithms.crossovers import UniformCrossover +from mlrose_ky.algorithms.crossovers import UniformCrossOver from mlrose_ky.algorithms.mutators import ChangeOneMutator from mlrose_ky.fitness.knapsack import Knapsack from mlrose_ky.opt_probs.discrete_opt import DiscreteOpt @@ -37,8 +37,8 @@ class KnapsackOpt(DiscreteOpt): max_weight_pct : float, default=0.35 Maximum allowable weight as a percentage of the total weight. - crossover : UniformCrossover, default=None - Crossover operation used for reproduction. If None, defaults to `UniformCrossover`. + crossover : UniformCrossOver, default=None + Crossover operation used for reproduction. If None, defaults to `UniformCrossOver`. mutator : ChangeOneMutator, default=None Mutation operation used for reproduction. If None, defaults to `ChangeOneMutator`. @@ -67,7 +67,7 @@ def __init__( weights: list[float] = None, values: list[float] = None, max_weight_pct: float = 0.35, - crossover: "UniformCrossover" = None, + crossover: "UniformCrossOver" = None, mutator: "ChangeOneMutator" = None, multiply_by_max_item_count: bool = False, ): @@ -94,7 +94,7 @@ def __init__( multiply_by_max_item_count=multiply_by_max_item_count, ) - crossover = UniformCrossover(self) if crossover is None else crossover + crossover = UniformCrossOver(self) if crossover is None else crossover mutator = ChangeOneMutator(self) if mutator is None else mutator super().__init__(length, fitness_fn, maximize, max_val, crossover, mutator) diff --git a/src/mlrose_ky/opt_probs/max_k_color_opt.py b/src/mlrose_ky/opt_probs/max_k_color_opt.py index 9139c0b5..d891ae86 100644 --- a/src/mlrose_ky/opt_probs/max_k_color_opt.py +++ b/src/mlrose_ky/opt_probs/max_k_color_opt.py @@ -8,7 +8,7 @@ import networkx as nx import numpy as np -from mlrose_ky.algorithms.crossovers import UniformCrossover +from mlrose_ky.algorithms.crossovers import UniformCrossOver from mlrose_ky.algorithms.mutators import ChangeOneMutator from mlrose_ky.fitness import MaxKColor from mlrose_ky.opt_probs.discrete_opt import DiscreteOpt @@ -34,8 +34,8 @@ class MaxKColorOpt(DiscreteOpt): max_colors : int, default=None Maximum number of colors to use for coloring the graph. - crossover : UniformCrossover, default=None - Crossover operation used for reproduction. If None, defaults to `UniformCrossover`. + crossover : UniformCrossOver, default=None + Crossover operation used for reproduction. If None, defaults to `UniformCrossOver`. mutator : ChangeOneMutator, default=None Mutation operation used for reproduction. If None, defaults to `ChangeOneMutator`. @@ -68,7 +68,7 @@ def __init__( fitness_fn: Any = None, maximize: bool = False, max_colors: int = None, - crossover: "UniformCrossover" = None, + crossover: "UniformCrossOver" = None, mutator: "ChangeOneMutator" = None, source_graph: nx.Graph = None, ): @@ -126,7 +126,7 @@ def __init__( self.max_val: int = max_colors # Use default crossover and mutator if none are provided - crossover = UniformCrossover(self) if crossover is None else crossover + crossover = UniformCrossOver(self) if crossover is None else crossover mutator = ChangeOneMutator(self) if mutator is None else mutator super().__init__(length, fitness_fn, maximize, max_colors, crossover, mutator) diff --git a/src/mlrose_ky/opt_probs/queens_opt.py b/src/mlrose_ky/opt_probs/queens_opt.py index 56a1d2cf..53bb490b 100644 --- a/src/mlrose_ky/opt_probs/queens_opt.py +++ b/src/mlrose_ky/opt_probs/queens_opt.py @@ -7,7 +7,7 @@ import numpy as np -from mlrose_ky.algorithms.crossovers import UniformCrossover +from mlrose_ky.algorithms.crossovers import UniformCrossOver from mlrose_ky.algorithms.mutators import ChangeOneMutator from mlrose_ky.fitness.queens import Queens from mlrose_ky.opt_probs.discrete_opt import DiscreteOpt @@ -27,8 +27,8 @@ class QueensOpt(DiscreteOpt): maximize : bool, default=False Whether to maximize the fitness function. Set :code:`False` for minimization problems. - crossover : UniformCrossover, default=None - Crossover operation used for reproduction. If None, defaults to `UniformCrossover`. + crossover : UniformCrossOver, default=None + Crossover operation used for reproduction. If None, defaults to `UniformCrossOver`. mutator : ChangeOneMutator, default=None Mutation operation used for reproduction. If None, defaults to `ChangeOneMutator`. @@ -53,7 +53,7 @@ def __init__( length: int = None, fitness_fn: Any = None, maximize: bool = False, - crossover: "UniformCrossover" = None, + crossover: "UniformCrossOver" = None, mutator: "ChangeOneMutator" = None, ): # Ensure that either fitness_fn or length is provided @@ -77,7 +77,7 @@ def __init__( self.max_val: int = length # Use default crossover and mutator if none are provided - crossover = UniformCrossover(self) if crossover is None else crossover + crossover = UniformCrossOver(self) if crossover is None else crossover mutator = ChangeOneMutator(self) if mutator is None else mutator super().__init__(length, fitness_fn, maximize, length, crossover, mutator) diff --git a/src/mlrose_ky/opt_probs/tsp_opt.py b/src/mlrose_ky/opt_probs/tsp_opt.py index e0c44504..29c4b82c 100644 --- a/src/mlrose_ky/opt_probs/tsp_opt.py +++ b/src/mlrose_ky/opt_probs/tsp_opt.py @@ -7,7 +7,7 @@ import numpy as np -from mlrose_ky.algorithms.crossovers import TSPCrossover +from mlrose_ky.algorithms.crossovers import TSPCrossOver from mlrose_ky.algorithms.mutators import SwapMutator from mlrose_ky.fitness import TravellingSales from mlrose_ky.opt_probs.discrete_opt import DiscreteOpt @@ -44,8 +44,8 @@ def __init__( length: int = None, fitness_fn: Any = None, maximize: bool = False, - coords: list[tuple[float, float]] = None, - distances: list[tuple[int, int, float]] = None, + coords: list[tuple] = None, + distances: list[tuple] = None, source_graph: Any = None, ): # Ensure that at least one of fitness_fn, coords, or distances is provided @@ -56,8 +56,8 @@ def __init__( if fitness_fn is None: fitness_fn = TravellingSales(coords=coords, distances=distances) - self.distances: list[tuple[int, int, float]] | None = distances - self.coords: list[tuple[float, float]] | None = coords + self.distances: list[tuple] | None = distances + self.coords: list[tuple] | None = coords # If length is not provided, infer it from coords or distances if length is None: @@ -69,8 +69,8 @@ def __init__( self.length: int = length - # Initialize the parent class with the TSPCrossover and SwapMutator - super().__init__(length, fitness_fn, maximize, max_val=length, crossover=TSPCrossover(self), mutator=SwapMutator(self)) + # Initialize the parent class with the TSPCrossOver and SwapMutator + super().__init__(length, fitness_fn, maximize, max_val=length, crossover=TSPCrossOver(self), mutator=SwapMutator(self)) # Ensure that the fitness function type is 'tsp' if self.fitness_fn.get_prob_type() != "tsp": diff --git a/src/mlrose_ky/runners/__init__.py b/src/mlrose_ky/runners/__init__.py index 7d3d991a..790b3bf6 100644 --- a/src/mlrose_ky/runners/__init__.py +++ b/src/mlrose_ky/runners/__init__.py @@ -3,11 +3,13 @@ # Authors: Andrew Rollings (modified by Kyle Nakamura) # License: BSD 3-clause -from ._nn_runner_base import _NNRunnerBase from .ga_runner import GARunner from .mimic_runner import MIMICRunner from .nngs_runner import NNGSRunner from .rhc_runner import RHCRunner from .sa_runner import SARunner from .skmlp_runner import SKMLPRunner + +from ._nn_runner_base import _NNRunnerBase + from .utils import build_data_filename diff --git a/src/mlrose_ky/runners/_nn_runner_base.py b/src/mlrose_ky/runners/_nn_runner_base.py index e1879ee3..deaa523b 100644 --- a/src/mlrose_ky/runners/_nn_runner_base.py +++ b/src/mlrose_ky/runners/_nn_runner_base.py @@ -150,17 +150,6 @@ def __init__( self.cv_results_df: pd.DataFrame | None = None self.best_params: dict | None = None - def dynamic_runner_name(self) -> str: - """ - Generates a dynamic name for the runner based on the class name and experiment name. - - Returns - ------- - str - The dynamic name for the runner. - """ - return f"{self.__class__.__name__}_{self._experiment_name}" - def run(self) -> tuple[pd.DataFrame | None, pd.DataFrame | None, pd.DataFrame | None, Any | None]: """ Executes the runner, performing grid search and handling the results. @@ -182,7 +171,7 @@ def run(self) -> tuple[pd.DataFrame | None, pd.DataFrame | None, pd.DataFrame | search_results = pk.load(pickle_file) else: run_start = time.perf_counter() - search_results = self.perform_grid_search( + search_results = self._perform_grid_search( classifier=self.classifier, parameters=self.grid_search_parameters, x_train=self.x_train, diff --git a/src/mlrose_ky/runners/_runner_base.py b/src/mlrose_ky/runners/_runner_base.py index 65e934b2..6c070551 100644 --- a/src/mlrose_ky/runners/_runner_base.py +++ b/src/mlrose_ky/runners/_runner_base.py @@ -34,67 +34,23 @@ class _RunnerBase(ABC): Attributes ---------- - _abort_flag : multiprocessing.Value + __abort : multiprocessing.Value Flag to signal abortion of the experiment. - _spawn_count : multiprocessing.Value + __spawn_count : multiprocessing.Value Tracks the number of spawned processes in parallel execution. - _replay_mode : multiprocessing.Value + __replay : multiprocessing.Value Indicates whether replay mode is active. - _original_sigint_handler : Any + __original_sigint_handler : Any Stores the original signal handler for Ctrl-C. - _sigint_params : tuple[int, Any] | None + __sigint_params : tuple[int, Any] | None Stores the signal and frame parameters when Ctrl-C is triggered. """ - _abort_flag: multiprocessing.Value = multiprocessing.Value(ctypes.c_bool) - _spawn_count: multiprocessing.Value = multiprocessing.Value(ctypes.c_uint) - _replay_mode: multiprocessing.Value = multiprocessing.Value(ctypes.c_bool) - _original_sigint_handler: Any = None - _sigint_params: tuple[int, Any] | None = None - - @classmethod - def get_runner_name(cls) -> str: - """Get a short name for the runner class.""" - return get_short_name(cls) - - def get_dynamic_runner_name(self) -> str: - """Get the dynamic name of the runner, if set, otherwise return the default runner name.""" - dynamic_runner_name = self._dynamic_short_name or self.get_runner_name() - - if not dynamic_runner_name: - raise ValueError("dynamic_runner_name is None") - - return dynamic_runner_name - - def set_dynamic_runner_name(self, name: str): - """Set a dynamic runner name.""" - self._dynamic_short_name = name - - @staticmethod - def _print_banner(text: str): - """Print a formatted banner for logging.""" - logging.info("*" * len(text)) - logging.info(text) - logging.info("*" * len(text)) - - @staticmethod - def _sanitize_value(value: Any) -> str: - """Sanitize a value for logging, handling different types appropriately.""" - if isinstance(value, (tuple, list)): - sanitized_value = str(value) - elif isinstance(value, np.ndarray): - sanitized_value = str(list(value)) - elif callable(value): - sanitized_value = get_short_name(value) - else: - sanitized_value = str(value) # Handle non-callable types like floats, ints, etc. - - return sanitized_value - - @abstractmethod - def run(self): - """Abstract method to be implemented by subclasses.""" - pass + __abort: multiprocessing.Value = multiprocessing.Value(ctypes.c_bool) + __spawn_count: multiprocessing.Value = multiprocessing.Value(ctypes.c_uint) + __replay: multiprocessing.Value = multiprocessing.Value(ctypes.c_bool) + __original_sigint_handler: Any = None + __sigint_params: tuple[int, Any] | None = None def __init__( self, @@ -169,40 +125,84 @@ def __init__( self._increment_spawn_count() + @classmethod + def runner_name(cls) -> str: + """Get a short name for the runner class.""" + return get_short_name(cls) + + def dynamic_runner_name(self) -> str: + """Get the dynamic name of the runner, if set, otherwise return the default runner name.""" + dynamic_runner_name = self._dynamic_short_name or self.runner_name() + + if not dynamic_runner_name: + raise ValueError("dynamic_runner_name is None") + + return dynamic_runner_name + + def _set_dynamic_runner_name(self, name: str): + """Set a dynamic runner name.""" + self._dynamic_short_name = name + + @staticmethod + def _print_banner(text: str): + """Print a formatted banner for logging.""" + logging.info("*" * len(text)) + logging.info(text) + logging.info("*" * len(text)) + + @staticmethod + def _sanitize_value(value: Any) -> str: + """Sanitize a value for logging, handling different types appropriately.""" + if isinstance(value, (tuple, list)): + sanitized_value = str(value) + elif isinstance(value, np.ndarray): + sanitized_value = str(list(value)) + elif callable(value): + sanitized_value = get_short_name(value) + else: + sanitized_value = str(value) # Handle non-callable types like floats, ints, etc. + + return sanitized_value + + @abstractmethod + def run(self): + """Abstract method to be implemented by subclasses.""" + pass + def _increment_spawn_count(self): """Increment the spawn count for the runner (used in parallel execution).""" - with self._spawn_count.get_lock(): - self._spawn_count.value += 1 + with self.__spawn_count.get_lock(): + self.__spawn_count.value += 1 def _decrement_spawn_count(self): """Decrement the spawn count for the runner.""" - with self._spawn_count.get_lock(): - self._spawn_count.value -= 1 + with self.__spawn_count.get_lock(): + self.__spawn_count.value -= 1 - def get_spawn_count(self) -> int: + def _get_spawn_count(self) -> int: """Return the current spawn count and log it.""" - self._print_banner(f"*** Spawn Count Remaining: {self._spawn_count.value} ***") - return self._spawn_count.value + self._print_banner(f"*** Spawn Count Remaining: {self.__spawn_count.value} ***") + return self.__spawn_count.value def abort(self): """Set the abort flag to signal that the runner should stop execution.""" self._print_banner("*** ABORTING ***") - with self._abort_flag.get_lock(): - self._abort_flag.value = True + with self.__abort.get_lock(): + self.__abort.value = True def has_aborted(self) -> bool: """Return whether the abort flag has been set.""" - return self._abort_flag.value + return self.__abort.value def set_replay_mode(self, value: bool = True): """Enable or disable replay mode, which reuses previous results.""" - with self._replay_mode.get_lock(): - self._replay_mode.value = value + with self.__replay.get_lock(): + self.__replay.value = value def replay_mode(self) -> bool: """Check if replay mode is enabled.""" - return self._replay_mode.value + return self.__replay.value def _setup(self): """Prepare the runner by clearing stats, setting up directories, and handling Ctrl-C interrupts.""" @@ -221,8 +221,8 @@ def _setup(self): # Set up Ctrl-C handler if necessary if self.override_ctrl_c_handler: - if self._original_sigint_handler is None: - self._original_sigint_handler = signal.getsignal(signal.SIGINT) + if self.__original_sigint_handler is None: + self.__original_sigint_handler = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, self._ctrl_c_handler) def _ctrl_c_handler(self, sig: int, frame: Any): @@ -237,7 +237,7 @@ def _ctrl_c_handler(self, sig: int, frame: Any): Current stack frame. """ logging.info("Interrupted - saving progress so far") - self._sigint_params = (sig, frame) + self.__sigint_params = (sig, frame) self.abort() def _tear_down(self): @@ -248,19 +248,19 @@ def _tear_down(self): try: # Restore the original Ctrl-C handler self._decrement_spawn_count() - if self._original_sigint_handler is not None: - signal.signal(signal.SIGINT, self._original_sigint_handler) - if self.has_aborted() and self.get_spawn_count() == 0: - sig, frame = self._sigint_params - self._original_sigint_handler(sig, frame) + if self.__original_sigint_handler is not None: + signal.signal(signal.SIGINT, self.__original_sigint_handler) + if self.has_aborted() and self._get_spawn_count() == 0: + sig, frame = self.__sigint_params + self.__original_sigint_handler(sig, frame) except (ValueError, TypeError, AttributeError, Exception) as e: logging.error(f"Problem restoring SIGINT handler: {e}") - def log_current_argument(self, arg_name: str, arg_value: Any): + def _log_current_argument(self, arg_name: str, arg_value: Any): """Log the current argument passed to the algorithm.""" self._current_logged_algorithm_args[arg_name] = arg_value - def run_experiment(self, algorithm: Any, **kwargs: Any) -> tuple[pd.DataFrame | None, pd.DataFrame | None]: + def run_experiment_(self, algorithm: Any, **kwargs: Any) -> tuple[pd.DataFrame | None, pd.DataFrame | None]: """ Execute the experiment with the provided algorithm and log the results. @@ -285,7 +285,7 @@ def run_experiment(self, algorithm: Any, **kwargs: Any) -> tuple[pd.DataFrame | value_sets = list(itertools.product(*values)) - logging.info(f"Running {self.get_dynamic_runner_name()}") + logging.info(f"Running {self.dynamic_runner_name()}") run_start = time.perf_counter() for value_set in value_sets: @@ -380,7 +380,7 @@ def _get_pickle_filename_root(self, name: str) -> str: """Generate the root filename for the pickle file based on experiment metadata.""" return build_data_filename( output_directory=self._output_directory, - runner_name=self.get_dynamic_runner_name(), + runner_name=self.dynamic_runner_name(), experiment_name=self._experiment_name, df_name=name, ) @@ -490,14 +490,14 @@ def _invoke_algorithm( kwargs = {k: v for k, v in total_args.items() if k in valid_args} # Reset the problem instance and run the algorithm - self.start_run_timing() + self._start_run_timing() problem.reset() result = algorithm( problem=problem, max_attempts=max_attempts, curve=curve, random_state=self.seed, - state_fitness_callback=self.save_state, + state_fitness_callback=self._save_state, callback_user_info=user_info, **kwargs, ) @@ -507,7 +507,7 @@ def _invoke_algorithm( return result - def start_run_timing(self): + def _start_run_timing(self): """Start timing the experiment's execution.""" self._run_start_time = time.perf_counter() @@ -543,7 +543,7 @@ def _create_curve_stat( return curve_stat - def save_state( + def _save_state( self, iteration: int, state: Any, @@ -598,7 +598,7 @@ def save_state( logging.debug(data_desc) logging.debug( - f"runner_name:[{self.get_dynamic_runner_name()}], experiment_name:[{self._experiment_name}], " + f"runner_name:[{self.dynamic_runner_name()}], experiment_name:[{self._experiment_name}], " + ("" if attempt is None else f"attempt:[{attempt}], ") + f"iteration:[{iteration}], done:[{done}], " f"time:[{t:.2f}], fitness:[{fitness:.4f}]" diff --git a/src/mlrose_ky/runners/ga_runner.py b/src/mlrose_ky/runners/ga_runner.py index 5095f3bc..9efb7659 100644 --- a/src/mlrose_ky/runners/ga_runner.py +++ b/src/mlrose_ky/runners/ga_runner.py @@ -117,7 +117,7 @@ def run(self) -> tuple[pd.DataFrame, pd.DataFrame]: tuple A tuple containing two DataFrames: run statistics and run curves """ - return super().run_experiment( + return super().run_experiment_( algorithm=mlrose_ky.genetic_alg, pop_size=("Population Size", self.population_sizes), mutation_prob=("Mutation Rate", self.mutation_rates), diff --git a/src/mlrose_ky/runners/mimic_runner.py b/src/mlrose_ky/runners/mimic_runner.py index 513b873e..e4f93783 100644 --- a/src/mlrose_ky/runners/mimic_runner.py +++ b/src/mlrose_ky/runners/mimic_runner.py @@ -112,7 +112,7 @@ def _setup(self): super()._setup() if self._use_fast_mimic is not None: - self.log_current_argument("use_fast_mimic", self._use_fast_mimic) + self._log_current_argument("use_fast_mimic", self._use_fast_mimic) def run(self) -> tuple[pd.DataFrame | None, pd.DataFrame | None]: """ @@ -126,7 +126,7 @@ def run(self) -> tuple[pd.DataFrame | None, pd.DataFrame | None]: tuple A tuple containing two DataFrames: run statistics and run curves """ - return super().run_experiment( + return super().run_experiment_( algorithm=mlrose_ky.mimic, pop_size=("Population Size", self.population_sizes), keep_pct=("Keep Percent", self.keep_percent_list), diff --git a/src/mlrose_ky/runners/nngs_runner.py b/src/mlrose_ky/runners/nngs_runner.py index 752ab464..c394f6e0 100644 --- a/src/mlrose_ky/runners/nngs_runner.py +++ b/src/mlrose_ky/runners/nngs_runner.py @@ -157,7 +157,7 @@ def __init__( ) # Update short name based on the algorithm - self.set_dynamic_runner_name(f"{get_short_name(self)}_{get_short_name(algorithm)}") + self._set_dynamic_runner_name(f"{get_short_name(self)}_{get_short_name(algorithm)}") def run_one_experiment_(self, algorithm: Any, total_args: dict, **params: dict) -> tuple | None: """ diff --git a/src/mlrose_ky/runners/rhc_runner.py b/src/mlrose_ky/runners/rhc_runner.py index ad3ac06a..898cac88 100644 --- a/src/mlrose_ky/runners/rhc_runner.py +++ b/src/mlrose_ky/runners/rhc_runner.py @@ -97,4 +97,4 @@ def run(self) -> tuple[pd.DataFrame | None, pd.DataFrame | None]: tuple A tuple containing two DataFrames: run statistics and run curves. """ - return super().run_experiment(algorithm=mlrose_ky.random_hill_climb, restarts=("Restarts", self.restart_list)) + return super().run_experiment_(algorithm=mlrose_ky.random_hill_climb, restarts=("Restarts", self.restart_list)) diff --git a/src/mlrose_ky/runners/sa_runner.py b/src/mlrose_ky/runners/sa_runner.py index a0fdf2f7..ba0679e7 100644 --- a/src/mlrose_ky/runners/sa_runner.py +++ b/src/mlrose_ky/runners/sa_runner.py @@ -123,4 +123,4 @@ def run(self) -> tuple[pd.DataFrame | None, pd.DataFrame | None]: temperatures = ( self.temperature_list if self.use_raw_temp else [d(init_temp=t) for t in self.temperature_list for d in self.decay_list] ) - return super().run_experiment(algorithm=mlrose_ky.simulated_annealing, schedule=("Temperature", temperatures)) + return super().run_experiment_(algorithm=mlrose_ky.simulated_annealing, schedule=("Temperature", temperatures)) diff --git a/src/mlrose_ky/runners/skmlp_runner.py b/src/mlrose_ky/runners/skmlp_runner.py index 6c6bc397..c8afc8e6 100644 --- a/src/mlrose_ky/runners/skmlp_runner.py +++ b/src/mlrose_ky/runners/skmlp_runner.py @@ -61,7 +61,7 @@ def __init__(self, runner: "SKMLPRunner", **kwargs): mlp_kwargs = {k: v for k, v in kwargs.items() if k in valid_args} self.mlp: MLPClassifier = MLPClassifier(**mlp_kwargs) - self.state_callback = self.runner.save_state + self.state_callback = self.runner._save_state self.fit_started_: bool = False self.user_info_: list[tuple[str, Any]] | None = None self.kwargs_: dict[str, Any] = kwargs @@ -131,7 +131,7 @@ def fit(self, x_train: np.ndarray, y_train: np.ndarray = None) -> MLPClassifier: The trained model. """ self.fit_started_ = True - self.runner.start_run_timing() + self.runner._start_run_timing() # Make initial callback self._invoke_runner_callback() @@ -258,7 +258,7 @@ def _invoke_runner_callback(self): if self.user_info_ is None: self.user_info_ = [(k, self.__dict__[k]) for k in self.kwargs_.keys() if hasattr(self, k)] for k, v in self.user_info_: - self.runner.log_current_argument(k, v) + self.runner._log_current_argument(k, v) self.state_callback( iteration=iterations, diff --git a/tests/test_gridsearch.py b/tests/test_gridsearch.py index b67d9d23..8eb643e2 100644 --- a/tests/test_gridsearch.py +++ b/tests/test_gridsearch.py @@ -66,7 +66,7 @@ def test_perform_grid_search(self, grid_search_mixin, sample_data, dummy_classif """Should perform grid search with a classifier and return GridSearchCV object""" X_train, X_test, y_train, y_test = sample_data - search_results = grid_search_mixin.perform_grid_search( + search_results = grid_search_mixin._perform_grid_search( classifier=dummy_classifier, x_train=X_train, y_train=y_train, cv=3, parameters=param_grid ) @@ -79,7 +79,7 @@ def test_perform_grid_search(self, grid_search_mixin, sample_data, dummy_classif def test_handle_empty_input(self, grid_search_mixin): """Should handle empty input data gracefully""" with pytest.raises(ValueError): - grid_search_mixin.perform_grid_search( + grid_search_mixin._perform_grid_search( classifier=DummyClassifier(), x_train=np.array([]), y_train=np.array([]), cv=3, parameters={"strategy": ["most_frequent"]} ) @@ -172,7 +172,7 @@ def test_perform_grid_search_with_verbose(self, grid_search_mixin, sample_data, X_train, X_test, y_train, y_test = sample_data # Perform grid search with verbose output enabled - search_results = grid_search_mixin.perform_grid_search( + search_results = grid_search_mixin._perform_grid_search( dummy_classifier, X_train, y_train, cv=3, parameters=grid_search_parameters, verbose=True ) @@ -187,7 +187,7 @@ def test_perform_grid_search_with_multiple_jobs(self, grid_search_mixin, sample_ X_train, X_test, y_train, y_test = sample_data # Perform grid search with n_jobs set to 2 - search_results = grid_search_mixin.perform_grid_search( + search_results = grid_search_mixin._perform_grid_search( dummy_classifier, X_train, y_train, cv=3, parameters=grid_search_parameters, n_jobs=2 ) diff --git a/tests/test_opt_probs/test_discrete_opt.py b/tests/test_opt_probs/test_discrete_opt.py index cf36872d..cec6f501 100644 --- a/tests/test_opt_probs/test_discrete_opt.py +++ b/tests/test_opt_probs/test_discrete_opt.py @@ -8,7 +8,7 @@ import mlrose_ky from mlrose_ky.opt_probs import DiscreteOpt from mlrose_ky.fitness import OneMax -from mlrose_ky.algorithms import OnePointCrossover +from mlrose_ky.algorithms import OnePointCrossOver class TestDiscreteOpt: @@ -164,7 +164,7 @@ def test_reproduce_mut1_max2(self): def test_reproduce_mut1_max_gt2(self): """Test reproduce method when mutation_prob is 1 and max_val is greater than 2""" problem = DiscreteOpt(5, OneMax(), max_val=3) - problem._crossover = OnePointCrossover(problem) + problem._crossover = OnePointCrossOver(problem) father = np.zeros(5) mother = np.ones(5) * 2 child = problem.reproduce(father, mother, mutation_prob=1) diff --git a/tests/test_opt_probs/test_opt_prob.py b/tests/test_opt_probs/test_opt_prob.py index 3c75e6de..bab16288 100644 --- a/tests/test_opt_probs/test_opt_prob.py +++ b/tests/test_opt_probs/test_opt_prob.py @@ -1,4 +1,4 @@ -"""Unit tests for opt_probs/opt_prob.py""" +"""Unit tests for opt_probs/_opt_prob.py""" # Author: Genevieve Hayes (modified by Kyle Nakamura) # License: BSD 3-clause @@ -6,7 +6,7 @@ import numpy as np from mlrose_ky.fitness import OneMax -from mlrose_ky.opt_probs.opt_prob import _OptProb +from mlrose_ky.opt_probs._opt_prob import _OptProb class TestOptProb: diff --git a/tests/test_runners/test_ga_runner.py b/tests/test_runners/test_ga_runner.py index 00b315be..2e6fe4fb 100644 --- a/tests/test_runners/test_ga_runner.py +++ b/tests/test_runners/test_ga_runner.py @@ -102,7 +102,7 @@ def test_garunner_initialization_with_additional_kwargs(self, problem, runner_kw runner = GARunner(**runner_kwargs, **additional_kwargs) assert runner.problem == problem - assert runner.get_runner_name() == "ga" + assert runner.runner_name() == "ga" assert runner._experiment_name == runner_kwargs["experiment_name"] assert runner.seed == runner_kwargs["seed"] assert runner.iteration_list == runner_kwargs["iteration_list"] diff --git a/tests/test_runners/test_mimic_runner.py b/tests/test_runners/test_mimic_runner.py index ae83007c..cedda520 100644 --- a/tests/test_runners/test_mimic_runner.py +++ b/tests/test_runners/test_mimic_runner.py @@ -97,7 +97,7 @@ def test_mimicrunner_initialization_with_additional_kwargs(self, problem, runner runner = MIMICRunner(**runner_kwargs, **additional_kwargs) assert runner.problem == problem - assert runner.get_runner_name() == "mimic" + assert runner.runner_name() == "mimic" assert runner._experiment_name == runner_kwargs["experiment_name"] assert runner.seed == runner_kwargs["seed"] assert runner.iteration_list == runner_kwargs["iteration_list"] diff --git a/tests/test_runners/test_nn_runner_base.py b/tests/test_runners/test_nn_runner_base.py index 7835e615..42168aed 100644 --- a/tests/test_runners/test_nn_runner_base.py +++ b/tests/test_runners/test_nn_runner_base.py @@ -55,7 +55,7 @@ def test_nn_runner_base_initialization(self): assert runner.verbose_grid_search is True assert runner.override_ctrl_c_handler is True assert runner.n_jobs == 1 - assert runner._replay_mode.value is False + assert runner.replay_mode() is False assert runner.cv_results_df is None assert runner.best_params is None @@ -96,7 +96,7 @@ def test_nn_runner_base_run_method(self): with ( patch.object(runner, "_setup", return_value=None) as mock_setup, - patch.object(runner, "perform_grid_search", return_value=mock_grid_search_result) as mock_grid_search, + patch.object(runner, "_perform_grid_search", return_value=mock_grid_search_result) as mock_grid_search, patch.object(runner, "_tear_down", return_value=None) as mock_tear_down, patch.object(runner, "_print_banner", return_value=None) as mock_print_banner, ): @@ -127,7 +127,7 @@ def test_nn_runner_base_teardown_removes_files(self): output_directory="test_output", ) - runner.get_runner_name = MagicMock(return_value="TestRunner") + runner.runner_name = MagicMock(return_value="TestRunner") runner.best_params = {"param1": 0.1, "param2": 1} runner._output_directory = "test_output" runner.replay_mode = MagicMock(return_value=False) diff --git a/tests/test_runners/test_rhc_runner.py b/tests/test_runners/test_rhc_runner.py index 6f2a7a2d..155751c0 100644 --- a/tests/test_runners/test_rhc_runner.py +++ b/tests/test_runners/test_rhc_runner.py @@ -69,7 +69,7 @@ def test_rhc_runner_initialization_with_additional_kwargs(self, problem, runner_ runner = RHCRunner(**runner_kwargs, **additional_kwargs) assert runner.problem == problem - assert runner.get_runner_name() == "rhc" + assert runner.runner_name() == "rhc" assert runner._experiment_name == runner_kwargs["experiment_name"] assert runner.seed == runner_kwargs["seed"] assert runner.iteration_list == runner_kwargs["iteration_list"] diff --git a/tests/test_runners/test_runner_base.py b/tests/test_runners/test_runner_base.py index 1e9f2ce6..509f640e 100644 --- a/tests/test_runners/test_runner_base.py +++ b/tests/test_runners/test_runner_base.py @@ -41,30 +41,30 @@ def _create_runner(**kwargs): def test_increment_spawn_count(self, test_runner): with patch("os.makedirs"), patch("os.path.exists", return_value=True): runner = test_runner() - initial_count = runner.get_spawn_count() + initial_count = runner._get_spawn_count() runner._increment_spawn_count() - assert runner.get_spawn_count() == initial_count + 1 + assert runner._get_spawn_count() == initial_count + 1 def test_decrement_spawn_count(self, test_runner): with patch("os.makedirs"), patch("os.path.exists", return_value=True): runner = test_runner() runner._increment_spawn_count() - initial_count = runner.get_spawn_count() + initial_count = runner._get_spawn_count() runner._decrement_spawn_count() - assert runner.get_spawn_count() == initial_count - 1 + assert runner._get_spawn_count() == initial_count - 1 def test_get_spawn_count(self, test_runner): with patch("os.makedirs"), patch("os.path.exists", return_value=True): runner = test_runner() - initial_spawn_count = runner.get_spawn_count() + initial_spawn_count = runner._get_spawn_count() runner._increment_spawn_count() - incremented_spawn_count = runner.get_spawn_count() + incremented_spawn_count = runner._get_spawn_count() assert incremented_spawn_count == initial_spawn_count + 1 runner._decrement_spawn_count() - decremented_spawn_count = runner.get_spawn_count() + decremented_spawn_count = runner._get_spawn_count() assert decremented_spawn_count == initial_spawn_count def test_abort_sets_abort_flag(self, test_runner): @@ -127,6 +127,6 @@ def test_log_current_argument(self, test_runner): runner = test_runner(seed=SEED, iteration_list=[0, 1, 2]) arg_name = "test_arg" arg_value = "test_value" - runner.log_current_argument(arg_name, arg_value) + runner._log_current_argument(arg_name, arg_value) assert runner._current_logged_algorithm_args[arg_name] == arg_value diff --git a/tests/test_runners/test_sa_runner.py b/tests/test_runners/test_sa_runner.py index 7218dc2a..2aa15973 100644 --- a/tests/test_runners/test_sa_runner.py +++ b/tests/test_runners/test_sa_runner.py @@ -84,7 +84,7 @@ def test_sarunner_initialization_with_additional_kwargs(self, problem, runner_kw runner = SARunner(**runner_kwargs, **additional_kwargs) assert runner.problem == problem - assert runner.get_runner_name() == "sa" + assert runner.runner_name() == "sa" assert runner._experiment_name == runner_kwargs["experiment_name"] assert runner.seed == runner_kwargs["seed"] assert runner.iteration_list == runner_kwargs["iteration_list"] diff --git a/tests/test_runners/test_skmlp_runner.py b/tests/test_runners/test_skmlp_runner.py index 94d8a872..66cdae32 100644 --- a/tests/test_runners/test_skmlp_runner.py +++ b/tests/test_runners/test_skmlp_runner.py @@ -83,7 +83,7 @@ def test_dynamic_runner_name(self, runner_kwargs): """Test that the runner name is set dynamically based on the algorithm.""" runner = SKMLPRunner(**runner_kwargs) expected_name = "skmlp" - assert runner.get_runner_name() == expected_name + assert runner.runner_name() == expected_name def test_grid_search_scorer_method(self, runner): """Test that the grid search scorer method is set correctly.""" @@ -102,6 +102,6 @@ def test_skmlp_runner_initialization_with_additional_kwargs(self, runner_kwargs) additional_kwargs = {"custom_arg": "custom_value"} runner = SKMLPRunner(**runner_kwargs, **additional_kwargs) - assert runner.get_runner_name() == "skmlp" + assert runner.runner_name() == "skmlp" assert runner.classifier.mlp.early_stopping == runner_kwargs["early_stopping"] assert runner.classifier.mlp.random_state == SEED