@File : init.py @Time : 2026/05/21 14:47:35 @Author : Alejandro Marrero (amarrerd@ull.edu.es) @Version : 1.0 @Contact : amarrerd@ull.edu.es @License : (C)Copyright 2026, Alejandro Marrero @Desc : None

BatchUniformMutation

Bases: Mutation

Source code in digneapy/operators/mutation/uniform.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class BatchUniformMutation(Mutation):
    def __init__(self, seed: Optional[int | np.random.SeedSequence] = None):
        super().__init__(seed)

    def __call__(
        self, population: np.ndarray, lb: np.ndarray, ub: np.ndarray
    ) -> np.ndarray:
        """Performs uniform one mutation in batches

        Args:
            population (np.ndarray): Batch of individuals to mutate
            lb (np.ndarray): Lower bound for each dimension
            ub (np.ndarray): Upper bound for each dimension
            seed (Optional[int  |  np.random.SeedSequence], optional): Seed for the random number generator. Defaults to None.

        Raises:
            ValueError: If the dimension of the individuals do not match the bounds

        Returns:
            np.ndarray: mutated population
        """
        dimension = len(population[0])
        n_individuals = len(population)

        if len(lb) != len(ub) or dimension != len(lb):
            msg = f"len of individuals ({dimension}) and bounds {len(lb)} differs in uniform_one_mutation"
            raise ValueError(msg)

        mutation_points = self._rng.integers(low=0, high=dimension, size=n_individuals)
        new_values = self._rng.uniform(
            low=lb[mutation_points], high=ub[mutation_points], size=n_individuals
        )

        population[np.arange(n_individuals), mutation_points] = new_values

        return population

__call__(population, lb, ub)

Performs uniform one mutation in batches

Parameters:
  • population (ndarray) –

    Batch of individuals to mutate

  • lb (ndarray) –

    Lower bound for each dimension

  • ub (ndarray) –

    Upper bound for each dimension

  • seed (Optional[int | SeedSequence]) –

    Seed for the random number generator. Defaults to None.

Raises:
  • ValueError

    If the dimension of the individuals do not match the bounds

Returns:
  • ndarray

    np.ndarray: mutated population

Source code in digneapy/operators/mutation/uniform.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
def __call__(
    self, population: np.ndarray, lb: np.ndarray, ub: np.ndarray
) -> np.ndarray:
    """Performs uniform one mutation in batches

    Args:
        population (np.ndarray): Batch of individuals to mutate
        lb (np.ndarray): Lower bound for each dimension
        ub (np.ndarray): Upper bound for each dimension
        seed (Optional[int  |  np.random.SeedSequence], optional): Seed for the random number generator. Defaults to None.

    Raises:
        ValueError: If the dimension of the individuals do not match the bounds

    Returns:
        np.ndarray: mutated population
    """
    dimension = len(population[0])
    n_individuals = len(population)

    if len(lb) != len(ub) or dimension != len(lb):
        msg = f"len of individuals ({dimension}) and bounds {len(lb)} differs in uniform_one_mutation"
        raise ValueError(msg)

    mutation_points = self._rng.integers(low=0, high=dimension, size=n_individuals)
    new_values = self._rng.uniform(
        low=lb[mutation_points], high=ub[mutation_points], size=n_individuals
    )

    population[np.arange(n_individuals), mutation_points] = new_values

    return population

ISOLineMutation

Bases: Mutation

Source code in digneapy/operators/mutation/iso.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class ISOLineMutation(Mutation):
    def __init__(
        self,
        sigma_iso: float,
        sigma_line: float,
        seed: Optional[int | np.random.SeedSequence] = None,
    ):
        super().__init__(seed)
        try:
            self._sigma_iso = float(sigma_iso)
            self._sigma_line = float(sigma_line)
        except ValueError:
            raise ValueError("sigma_iso and sigma_line must be float.")

    def __call__(
        self, population: np.ndarray, lb: np.ndarray, ub: np.ndarray
    ) -> np.ndarray:
        """Performs ISO+Line mutation from Vassiliades & Mouret 2018

        Args:
            population (np.ndarray): Batch of individuals to mutate
            lb (np.ndarray): Lower bound for each dimension
            ub (np.ndarray): Upper bound for each dimension

        Raises:
            ValueError: if dimension != bounds

        Returns:
            np.ndarray: Newly mutated individuals
        """
        dimension = len(population[0])
        if len(lb) != len(ub) or dimension != len(lb):
            msg = f"The size of individuals ({dimension}) and bounds {len(lb)} is different in iso_line_mutation"
            raise ValueError(msg)
        indices = np.arange(len(population))

        parents_a = np.asarray(
            population[self._rng.choice(indices, size=len(population))], copy=True
        )
        parents_b = np.asarray(
            population[self._rng.choice(indices, size=len(population))], copy=True
        )
        iso_noise = self._rng.normal(0, self._sigma_iso, size=parents_a.shape)
        line_steps = self._rng.uniform(0, self._sigma_line, size=(len(parents_a), 1))
        direction = parents_b - parents_a
        offspring = parents_a + iso_noise + line_steps * direction
        offspring = np.clip(offspring, lb, ub)
        return offspring

__call__(population, lb, ub)

Performs ISO+Line mutation from Vassiliades & Mouret 2018

Parameters:
  • population (ndarray) –

    Batch of individuals to mutate

  • lb (ndarray) –

    Lower bound for each dimension

  • ub (ndarray) –

    Upper bound for each dimension

Raises:
  • ValueError

    if dimension != bounds

Returns:
  • ndarray

    np.ndarray: Newly mutated individuals

Source code in digneapy/operators/mutation/iso.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def __call__(
    self, population: np.ndarray, lb: np.ndarray, ub: np.ndarray
) -> np.ndarray:
    """Performs ISO+Line mutation from Vassiliades & Mouret 2018

    Args:
        population (np.ndarray): Batch of individuals to mutate
        lb (np.ndarray): Lower bound for each dimension
        ub (np.ndarray): Upper bound for each dimension

    Raises:
        ValueError: if dimension != bounds

    Returns:
        np.ndarray: Newly mutated individuals
    """
    dimension = len(population[0])
    if len(lb) != len(ub) or dimension != len(lb):
        msg = f"The size of individuals ({dimension}) and bounds {len(lb)} is different in iso_line_mutation"
        raise ValueError(msg)
    indices = np.arange(len(population))

    parents_a = np.asarray(
        population[self._rng.choice(indices, size=len(population))], copy=True
    )
    parents_b = np.asarray(
        population[self._rng.choice(indices, size=len(population))], copy=True
    )
    iso_noise = self._rng.normal(0, self._sigma_iso, size=parents_a.shape)
    line_steps = self._rng.uniform(0, self._sigma_line, size=(len(parents_a), 1))
    direction = parents_b - parents_a
    offspring = parents_a + iso_noise + line_steps * direction
    offspring = np.clip(offspring, lb, ub)
    return offspring

UniformMutation

Bases: Mutation

Source code in digneapy/operators/mutation/uniform.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class UniformMutation(Mutation):
    def __init__(self, seed: Optional[int | np.random.SeedSequence] = None):
        super().__init__(seed)

    def __call__(self, individual: IndType, lb: np.ndarray, ub: np.ndarray) -> IndType:
        """Performs Uniform One Mutation on Instances and Solution objects.

        Args:
            individual (IndType): Instance or Solution to mutate.
            lb (np.ndarray): Lower bound for each dimension
            ub (np.ndarray): Upper bound for each dimension
            seed (Optional[int  |  np.random.SeedSequence], optional): Seed for the random number generator. Defaults to None.

        Raises:
            ValueError: If bouns != dimension

        Returns:
            IndType: Newly mutated individual
        """
        if len(lb) != len(ub) or len(individual) != len(lb):
            msg = f"The size of individual ({len(individual)}) and bounds {len(lb)} is different in uniform_one_mutation."
            raise ValueError(msg)

        mutation_point = self._rng.integers(low=0, high=len(individual))
        new_value = self._rng.uniform(low=lb[mutation_point], high=ub[mutation_point])
        individual[mutation_point] = new_value
        return individual

__call__(individual, lb, ub)

Performs Uniform One Mutation on Instances and Solution objects.

Parameters:
  • individual (IndType) –

    Instance or Solution to mutate.

  • lb (ndarray) –

    Lower bound for each dimension

  • ub (ndarray) –

    Upper bound for each dimension

  • seed (Optional[int | SeedSequence]) –

    Seed for the random number generator. Defaults to None.

Raises:
  • ValueError

    If bouns != dimension

Returns:
  • IndType( IndType ) –

    Newly mutated individual

Source code in digneapy/operators/mutation/uniform.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def __call__(self, individual: IndType, lb: np.ndarray, ub: np.ndarray) -> IndType:
    """Performs Uniform One Mutation on Instances and Solution objects.

    Args:
        individual (IndType): Instance or Solution to mutate.
        lb (np.ndarray): Lower bound for each dimension
        ub (np.ndarray): Upper bound for each dimension
        seed (Optional[int  |  np.random.SeedSequence], optional): Seed for the random number generator. Defaults to None.

    Raises:
        ValueError: If bouns != dimension

    Returns:
        IndType: Newly mutated individual
    """
    if len(lb) != len(ub) or len(individual) != len(lb):
        msg = f"The size of individual ({len(individual)}) and bounds {len(lb)} is different in uniform_one_mutation."
        raise ValueError(msg)

    mutation_point = self._rng.integers(low=0, high=len(individual))
    new_value = self._rng.uniform(low=lb[mutation_point], high=ub[mutation_point])
    individual[mutation_point] = new_value
    return individual