49 lines
1.5 KiB
Python
49 lines
1.5 KiB
Python
|
|
import numpy as np
|
||
|
|
|
||
|
|
from abc import ABC, abstractmethod
|
||
|
|
from functions import Function
|
||
|
|
from typing import Iterable, Tuple
|
||
|
|
|
||
|
|
|
||
|
|
class Solver(ABC):
|
||
|
|
def __init__(self, function: Function):
|
||
|
|
self.function = function
|
||
|
|
|
||
|
|
@abstractmethod
|
||
|
|
def rank(self, samples: Iterable[Iterable[float]], elite_size: int) -> (Iterable[Tuple], Iterable[Tuple], float):
|
||
|
|
pass
|
||
|
|
|
||
|
|
@abstractmethod
|
||
|
|
def sample(self, n: int) -> Iterable[float]:
|
||
|
|
pass
|
||
|
|
|
||
|
|
@abstractmethod
|
||
|
|
def update(elite: Iterable[Tuple]):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class SimpleEvolutionStrategy(Solver):
|
||
|
|
def __init__(self, function: Function, mu: Iterable[float], sigma: Iterable[float] = None):
|
||
|
|
if sigma and len(mu) != len(sigma):
|
||
|
|
raise Exception('Length of mu and sigma must match')
|
||
|
|
super().__init__(function)
|
||
|
|
self.mu = mu
|
||
|
|
if sigma:
|
||
|
|
self.sigma = sigma
|
||
|
|
else:
|
||
|
|
self.sigma = [1] * len(mu)
|
||
|
|
|
||
|
|
def rank(self, samples: Iterable[Iterable[float]], elite_size: int) -> (Iterable[Tuple], Iterable[float]):
|
||
|
|
fitness = self.function.eval(*samples.transpose())
|
||
|
|
samples = samples[np.argsort(fitness)]
|
||
|
|
fitness = np.sort(fitness)
|
||
|
|
elite = samples[0:elite_size]
|
||
|
|
return elite, fitness[0]
|
||
|
|
|
||
|
|
def sample(self, n: int) -> Iterable[Iterable[float]]:
|
||
|
|
return np.array([np.random.multivariate_normal(self.mu, np.diag(self.sigma)) for _ in range(n)])
|
||
|
|
|
||
|
|
def update(self, elite: Iterable[Tuple]):
|
||
|
|
self.mu = elite[0]
|
||
|
|
|