From 30a610ccf685e1a2f0ad85506fe3bc8bcfe7be01 Mon Sep 17 00:00:00 2001 From: "Tammo.Weber" Date: Tue, 16 Dec 2025 16:25:00 +0100 Subject: [PATCH] Hansen Skript roh --- Hansen_ES_CMA.py | 119 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 Hansen_ES_CMA.py diff --git a/Hansen_ES_CMA.py b/Hansen_ES_CMA.py new file mode 100644 index 0000000..881ff93 --- /dev/null +++ b/Hansen_ES_CMA.py @@ -0,0 +1,119 @@ +import numpy as np + + +def felli(x): + 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(): + #Initialization + + # User defined input parameters + N = 10 + xmean = np.random.rand(N) + sigma = 0.5 + stopfitness = 1e-10 + 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_) + + while counteval < stopeval: + + # 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] = felli(arx[:, k]) + 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 + + # 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("warning: flat fitness, consider reformulating the objective") + + print(f"{counteval}: {arfitness[0]}") + + #Final Message + print(f"{counteval}: {arfitness[0]}") + xmin = arx[:, arindex[0]] + return xmin + + +if __name__ == "__main__": + xmin = escma() + print("Bestes gefundenes x:", xmin) + print("f(xmin) =", felli(xmin))