# Copyright (c) 2022 AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import random
from typing import Any, Dict, List, Optional, Tuple
from discrete_optimization.generic_tools.do_mutation import (
LocalMove,
LocalMoveDefault,
Mutation,
)
from discrete_optimization.generic_tools.do_problem import (
Problem,
Solution,
TypeAttribute,
lower_bound_vector_encoding_from_dict,
upper_bound_vector_encoding_from_dict,
)
from discrete_optimization.generic_tools.mutations.mutation_util import (
get_attribute_for_type,
)
[docs]
class MutationIntegerSpecificArity(Mutation):
[docs]
@staticmethod
def build(
problem: Problem, solution: Solution, **kwargs: Any
) -> "MutationIntegerSpecificArity":
return MutationIntegerSpecificArity(
problem,
attribute=kwargs.get("attribute", None),
arities=kwargs.get("arities", None),
probability_flip=kwargs.get("probability_flip", 0.1),
min_value=kwargs.get("min_value", 1),
)
def __init__(
self,
problem: Problem,
attribute: Optional[str] = None,
arities: Optional[List[int]] = None,
probability_flip: float = 0.1,
min_value: int = 1,
):
self.problem = problem
self.probability_flip = probability_flip
lows = None
ups = None
register = problem.get_attribute_register()
if attribute is None:
attribute_key = get_attribute_for_type(
register, TypeAttribute.LIST_INTEGER_SPECIFIC_ARITY
)
self.attribute = register.dict_attribute_to_type[attribute_key]["name"]
else:
self.attribute = attribute
self.lows = lower_bound_vector_encoding_from_dict(
register.dict_attribute_to_type[self.attribute]
)
self.ups = upper_bound_vector_encoding_from_dict(
register.dict_attribute_to_type[self.attribute]
)
self.range_arities = [
list(range(l, up + 1)) for l, up in zip(self.lows, self.ups)
]
self.size = len(self.range_arities)
[docs]
def mutate(self, solution: Solution) -> Tuple[Solution, LocalMove]:
s2 = solution.copy()
vector = getattr(s2, self.attribute)
for k in range(self.size):
if random.random() <= self.probability_flip:
new_arity = random.choice(self.range_arities[k])
vector[k] = new_arity
setattr(s2, self.attribute, vector)
return s2, LocalMoveDefault(solution, s2)
[docs]
def mutate_and_compute_obj(
self, solution: Solution
) -> Tuple[Solution, LocalMove, Dict[str, float]]:
s, m = self.mutate(solution)
obj = self.problem.evaluate(s)
return s, m, obj