Abgabe fertig

This commit is contained in:
2026-02-11 12:08:46 +01:00
parent 5a293a823a
commit 59ad560f36
38 changed files with 3419 additions and 8763 deletions

157
ES/Hansen_ES_CMA.py Normal file
View File

@@ -0,0 +1,157 @@
import numpy as np
from numpy.typing import NDArray
def felli(x: NDArray) -> float:
N = x.shape[0]
if N < 2:
raise ValueError("dimension must be greater than one")
exponents = np.arange(N) / (N - 1)
return float(np.sum((1e6 ** exponents) * (x ** 2)))
def escma(func, *, N=10, xmean=None, sigma=0.5, stopfitness=1e-14, stopeval=2000,
func_args=(), func_kwargs=None, seed=0,
bestEver=np.inf, noImproveGen=0, absTolImprove=1e-12, maxNoImproveGen=100, sigmaImprove=1e-12):
if func_kwargs is None:
func_kwargs = {}
if seed is not None:
np.random.seed(seed)
# Initialization (aus Parametern statt hart verdrahtet)
if xmean is None:
xmean = np.random.rand(N)
else:
xmean = np.asarray(xmean, dtype=float)
N = xmean.shape[0]
if stopeval is None:
stopeval = int(1e3 * N ** 2)
# Strategy parameter setting: Selection
lambda_ = 4 + int(np.floor(3 * np.log(N)))
mu = lambda_ / 2.0
# muXone recombination weights
weights = np.log(mu + 0.5) - np.log(np.arange(1, int(mu) + 1))
mu = int(np.floor(mu))
weights = weights / np.sum(weights)
mueff = np.sum(weights) ** 2 / np.sum(weights ** 2)
# Strategy parameter setting: Adaptation
cc = (4 + mueff / N) / (N + 4 + 2 * mueff / N)
cs = (mueff + 2) / (N + mueff + 5)
c1 = 2 / ((N + 1.3) ** 2 + mueff)
cmu = min(1 - c1,
2 * (mueff - 2 + 1 / mueff) / ((N + 2) ** 2 + 2 * mueff))
damps = 1 + 2 * max(0, np.sqrt((mueff - 1) / (N + 1)) - 1) + cs
# Initialize dynamic (internal) strategy parameters and constants
pc = np.zeros(N)
ps = np.zeros(N)
B = np.eye(N)
D = np.eye(N)
C = B @ D @ (B @ D).T
eigeneval = 0
chiN = np.sqrt(N) * (1 - 1 / (4 * N) + 1 / (21 * N ** 2))
# Generation Loop
counteval = 0
arx = np.zeros((N, lambda_))
arz = np.zeros((N, lambda_))
arfitness = np.zeros(lambda_)
gen = 0
# print(f' [CMA-ES] Start: lambda = {lambda_}, sigma ={round(sigma, 6)}, stopeval = {stopeval}')
while counteval < stopeval:
gen += 1
# Generate and evaluate lambda offspring
for k in range(lambda_):
arz[:, k] = np.random.randn(N)
arx[:, k] = xmean + sigma * (B @ D @ arz[:, k])
arfitness[k] = float(func(arx[:, k], *func_args, **func_kwargs)) # <-- allgemein
counteval += 1
# Sort by fitness and compute weighted mean into xmean
idx = np.argsort(arfitness)
arfitness = arfitness[idx]
arindex = idx
xold = xmean.copy()
xmean = arx[:, arindex[:mu]] @ weights
zmean = arz[:, arindex[:mu]] @ weights
# Stagnation check
fbest = arfitness[0]
if bestEver - fbest > absTolImprove:
bestEver = fbest
noImproveGen = 0
else:
noImproveGen += 1
if gen == 1 or gen % 50 == 0:
# print(f' [CMA-ES] Gen {gen}, best = {round(fbest, 6)}, sigma = {sigma:.3g}')
pass
if noImproveGen >= maxNoImproveGen:
# print(f' [CMA-ES] Abbruch: keine Verbesserung > {round(absTolImprove, 3)} in {maxNoImproveGen} Generationen.')
break
if sigma < sigmaImprove:
# print(f' [CMA-ES] Abbruch: sigma zu klein {sigma:.3g}')
break
# Cumulation: Update evolution paths
ps = (1 - cs) * ps + np.sqrt(cs * (2 - cs) * mueff) * (B @ zmean)
norm_ps = np.linalg.norm(ps)
hsig = norm_ps / np.sqrt(1 - (1 - cs) ** (2 * counteval / lambda_)) / chiN < (1.4 + 2 / (N + 1))
hsig = 1.0 if hsig else 0.0
pc = (1 - cc) * pc + hsig * np.sqrt(cc * (2 - cc) * mueff) * (B @ D @ zmean)
# Adapt covariance matrix C
BDz = B @ D @ arz[:, arindex[:mu]]
C = (1 - c1 - cmu) * C \
+ c1 * (np.outer(pc, pc) + (1 - hsig) * cc * (2 - cc) * C) \
+ cmu * BDz @ np.diag(weights) @ BDz.T
# Adapt step-size sigma
sigma = sigma * np.exp((cs / damps) * (norm_ps / chiN - 1))
# Update B and D from C (Eigenzerlegung, O(N^2))
if counteval - eigeneval > lambda_ / ((c1 + cmu) * N * 10):
eigeneval = counteval
# enforce symmetry
C = (C + C.T) / 2.0
eigvals, B = np.linalg.eigh(C)
D = np.diag(np.sqrt(eigvals))
# Break, if fitness is good enough
if arfitness[0] <= stopfitness:
break
# Escape flat fitness, or better terminate?
if arfitness[0] == arfitness[int(np.ceil(0.7 * lambda_)) - 1]:
sigma = sigma * np.exp(0.2 + cs / damps)
# print(' [CMA-ES] stopfitness erreicht.')
# print("warning: flat fitness, consider reformulating the objective")
break
# print(f"{counteval}: {arfitness[0]}")
# Final Message
# print(f"{counteval}: {arfitness[0]}")
xmin = arx[:, arindex[0]]
bestValue = arfitness[0]
# print(f' [CMA-ES] Ende: Gen = {gen}, best = {round(bestValue, 6)}')
return xmin
if __name__ == "__main__":
xmin = escma(felli, N=10) # <-- Zielfunktion wird übergeben
print("Bestes gefundenes x:", xmin)
print("f(xmin) =", felli(xmin))