|
4 | 4 |
|
5 | 5 | import numpy |
6 | 6 | from moocore import hv_contributions |
7 | | -from scipy.spatial.distance import euclidean |
| 7 | +import numpy as np |
| 8 | +from scipy.spatial.distance import cdist |
8 | 9 |
|
9 | 10 | from jmetal.logger import get_logger |
10 | 11 | from jmetal.util.comparator import Comparator, SolutionAttributeComparator |
@@ -110,18 +111,19 @@ def compute_density_estimator(self, solutions: List[S]): |
110 | 111 | if solutions_size <= self.k: |
111 | 112 | return |
112 | 113 |
|
113 | | - # Compute distance matrix |
114 | | - self.distance_matrix = numpy.zeros(shape=(solutions_size, solutions_size)) |
115 | | - for i in range(solutions_size): |
116 | | - for j in range(solutions_size): |
117 | | - self.distance_matrix[i, j] = self.distance_matrix[j, i] = euclidean( |
118 | | - solutions[i].objectives, solutions[j].objectives |
119 | | - ) |
| 114 | + # Extract objectives as a 2D numpy array for vectorized operations |
| 115 | + objectives = np.array([s.objectives for s in solutions]) |
| 116 | + |
| 117 | + # Compute pairwise distances using cdist (much faster than nested loops) |
| 118 | + self.distance_matrix = cdist(objectives, objectives, 'euclidean') |
| 119 | + |
| 120 | + # Get k-th nearest neighbor distance for each solution |
| 121 | + # Using np.partition which is O(n) instead of full sort O(n log n) |
| 122 | + k_distances = np.partition(self.distance_matrix, kth=self.k, axis=1)[:, self.k] |
| 123 | + |
120 | 124 | # Assign knn_density attribute |
121 | | - for i in range(solutions_size): |
122 | | - distances = list(self.distance_matrix[i]) |
123 | | - distances.sort() |
124 | | - solutions[i].attributes["knn_density"] = distances[self.k] |
| 125 | + for i, dist in enumerate(k_distances): |
| 126 | + solutions[i].attributes["knn_density"] = dist |
125 | 127 |
|
126 | 128 | def sort(self, solutions: List[S]) -> List[S]: |
127 | 129 | """ |
|
0 commit comments