Files
evolution-strategies/solvers.py
Daniel Lukats 14c7756802 added schaffer2 function
added output for improvement of fitness
added CMAES algorithm, that requires further testing
2019-09-23 14:11:46 +02:00

84 lines
3.0 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[Iterable[float]], float):
pass
@abstractmethod
def sample(self, n: int) -> Iterable[float]:
pass
@abstractmethod
def update(elite: Iterable[Iterable[float]]):
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[Iterable[float]], 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[Iterable[float]]):
self.mu = elite[0]
class CMAEvolutionStrategy(Solver):
def __init__(self, function: Function, mu: Iterable[float], covariances: Iterable[float] = None):
if covariances is not None and len(mu) != covariances.shape[0] and len(mu) != covariances.shape[1]:
raise Exception('Length of mu and covariance matrix must match')
super().__init__(function)
self.mu = mu
if covariances is not None:
self.covariances = covariances
else:
self.covariances = np.array([[1.0, 0.0], [0.0, 1.0]])
def rank(self, samples: Iterable[Iterable[float]], elite_size: int) -> (Iterable[Iterable[float]], 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, self.covariances) for _ in range(n)])
def update(self, elite: Iterable[Iterable[float]]):
mu = self.mu
x = elite.transpose()[0]
y = elite.transpose()[1]
self.mu[0] = np.average(x)
self.mu[1] = np.average(y)
# TODO fix covariance matrix calculation using the tutorial by Nikolaus Hansen
self.covariances[0][0] = np.average((x - mu[0])**2)
self.covariances[1][1] = np.average((y - mu[1])**2)
self.covariances[0][1] = np.average((x - mu[0]) * (y - mu[1]))
# self.covariances = np.cov(elite.transpose())