Spaces:
No application file
No application file
#! /usr/bin/env python | |
#| This file is a part of the pymap_elites framework. | |
#| Copyright 2019, INRIA | |
#| Main contributor(s): | |
#| Jean-Baptiste Mouret, [email protected] | |
#| Eloise Dalin , [email protected] | |
#| Pierre Desreumaux , [email protected] | |
#| | |
#| | |
#| **Main paper**: Mouret JB, Clune J. Illuminating search spaces by | |
#| mapping elites. arXiv preprint arXiv:1504.04909. 2015 Apr 20. | |
#| | |
#| This software is governed by the CeCILL license under French law | |
#| and abiding by the rules of distribution of free software. You | |
#| can use, modify and/ or redistribute the software under the terms | |
#| of the CeCILL license as circulated by CEA, CNRS and INRIA at the | |
#| following URL "http://www.cecill.info". | |
#| | |
#| As a counterpart to the access to the source code and rights to | |
#| copy, modify and redistribute granted by the license, users are | |
#| provided only with a limited warranty and the software's author, | |
#| the holder of the economic rights, and the successive licensors | |
#| have only limited liability. | |
#| | |
#| In this respect, the user's attention is drawn to the risks | |
#| associated with loading, using, modifying and/or developing or | |
#| reproducing the software by the user in light of its specific | |
#| status of free software, that may mean that it is complicated to | |
#| manipulate, and that also therefore means that it is reserved for | |
#| developers and experienced professionals having in-depth computer | |
#| knowledge. Users are therefore encouraged to load and test the | |
#| software's suitability as regards their requirements in conditions | |
#| enabling the security of their systems and/or data to be ensured | |
#| and, more generally, to use and operate it in the same conditions | |
#| as regards security. | |
#| | |
#| The fact that you are presently reading this means that you have | |
#| had knowledge of the CeCILL license and that you accept its terms. | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import matplotlib | |
from scipy.spatial import Voronoi, voronoi_plot_2d | |
import sys | |
from matplotlib.ticker import FuncFormatter | |
from sklearn.neighbors import KDTree | |
import matplotlib.cm as cm | |
my_cmap = cm.viridis | |
def voronoi_finite_polygons_2d(vor, radius=None): | |
""" | |
Reconstruct infinite voronoi regions in a 2D diagram to finite | |
regions. | |
Source: https://stackoverflow.com/questions/20515554/colorize-voronoi-diagram/20678647#20678647 | |
Parameters | |
---------- | |
vor : Voronoi | |
Input diagram | |
radius : float, optional | |
Distance to 'points at infinity'. | |
Returns | |
------- | |
regions : list of tuples | |
Indices of vertices in each revised Voronoi regions. | |
vertices : list of tuples | |
Coordinates for revised Voronoi vertices. Same as coordinates | |
of input vertices, with 'points at infinity' appended to the | |
end. | |
""" | |
if vor.points.shape[1] != 2: | |
raise ValueError("Requires 2D input") | |
new_regions = [] | |
new_vertices = vor.vertices.tolist() | |
center = vor.points.mean(axis=0) | |
if radius is None: | |
radius = vor.points.ptp().max() | |
# Construct a map containing all ridges for a given point | |
all_ridges = {} | |
for (p1, p2), (v1, v2) in zip(vor.ridge_points, vor.ridge_vertices): | |
all_ridges.setdefault(p1, []).append((p2, v1, v2)) | |
all_ridges.setdefault(p2, []).append((p1, v1, v2)) | |
# Reconstruct infinite regions | |
for p1, region in enumerate(vor.point_region): | |
vertices = vor.regions[region] | |
if all(v >= 0 for v in vertices): | |
# finite region | |
new_regions.append(vertices) | |
continue | |
# reconstruct a non-finite region | |
ridges = all_ridges[p1] | |
new_region = [v for v in vertices if v >= 0] | |
for p2, v1, v2 in ridges: | |
if v2 < 0: | |
v1, v2 = v2, v1 | |
if v1 >= 0: | |
# finite ridge: already in the region | |
continue | |
# Compute the missing endpoint of an infinite ridge | |
t = vor.points[p2] - vor.points[p1] # tangent | |
t /= np.linalg.norm(t) | |
n = np.array([-t[1], t[0]]) # normal | |
midpoint = vor.points[[p1, p2]].mean(axis=0) | |
direction = np.sign(np.dot(midpoint - center, n)) * n | |
far_point = vor.vertices[v2] + direction * radius | |
new_region.append(len(new_vertices)) | |
new_vertices.append(far_point.tolist()) | |
# sort region counterclockwise | |
vs = np.asarray([new_vertices[v] for v in new_region]) | |
c = vs.mean(axis=0) | |
angles = np.arctan2(vs[:,1] - c[1], vs[:,0] - c[0]) | |
new_region = np.array(new_region)[np.argsort(angles)] | |
# finish | |
new_regions.append(new_region.tolist()) | |
return new_regions, np.asarray(new_vertices) | |
def load_data(filename, dim,dim_x): | |
print("Loading ",filename) | |
data = np.loadtxt(filename) | |
fit = data[:, 0:1] | |
desc = data[:,1: dim+1] | |
x = data[:,dim+1:dim+1+dim_x] | |
return fit, desc, x | |
def load_centroids(filename): | |
points = np.loadtxt(filename) | |
return points | |
def plot_cvt(ax, centroids, fit, desc, x,dim1,dim2, min_fit, max_fit): | |
# compute Voronoi tesselation | |
print("Voronoi...") | |
vor = Voronoi(centroids[:,0:2]) | |
regions, vertices = voronoi_finite_polygons_2d(vor) | |
print("fit:", min_fit, max_fit) | |
norm = matplotlib.colors.Normalize(vmin=min_fit, vmax=max_fit) | |
print("KD-Tree...") | |
kdt = KDTree(centroids, leaf_size = 30, metric = 'euclidean') | |
print("plotting contour...") | |
#ax.scatter(centroids[:, 0], centroids[:,1], c=fit) | |
# contours | |
for i, region in enumerate(regions): | |
polygon = vertices[region] | |
ax.fill(*zip(*polygon), alpha=0.05, edgecolor='black', facecolor='white', lw=1) | |
print("plotting data...") | |
k = 0 | |
for i in range(0, len(desc)): | |
q = kdt.query([desc[i]], k = 1) | |
index = q[1][0][0] | |
region = regions[index] | |
polygon = vertices[region] | |
ax.fill(*zip(*polygon), alpha=0.9, color=my_cmap(norm(fit[i]))[0]) | |
k += 1 | |
if k % 100 == 0: | |
print(k, end=" ", flush=True) | |
fit_reshaped = fit.reshape((len(fit),)) | |
sc = ax.scatter(desc[:,0], desc[:,1], c=fit_reshaped, cmap=my_cmap, s=10, zorder=0) | |
if __name__ == "__main__": | |
if len(sys.argv) < 3: | |
sys.exit('Usage: %s centroids_file archive.dat [min_fit] [max_fit]' % sys.argv[0]) | |
centroids = load_centroids(sys.argv[1]) | |
dim_x = 100 | |
fit, beh, x = load_data(sys.argv[2], centroids.shape[1], dim_x) | |
print("Fitness max : ", max(fit)) | |
index = np.argmax(fit) | |
print("Average fit:", fit.sum() / fit.shape[0]) | |
print("Associated desc : " , beh[index] ) | |
print("Associated ctrl : " , x[index] ) | |
print("Index : ", index) | |
print("total len ",len(fit)) | |
if len(sys.argv) > 3: | |
min_fit = float(sys.argv[3]) | |
max_fit = float(sys.argv[4]) | |
else: | |
min_fit = min(fit) | |
max_fit = max(fit) | |
print("Min = {} Max={}".format(min_fit, max_fit)) | |
# Plot | |
fig, axes = plt.subplots(1, 1, figsize=(10, 10), facecolor='white', edgecolor='white') | |
axes.set_xlim(0, 1) | |
axes.set_ylim(0, 1) | |
plot_cvt(axes, centroids, fit, beh, x,2,4, min_fit, max_fit) | |
fig.savefig('cvt.pdf') | |
fig.savefig('cvt.png') | |