Skip to content

Commit 7210b07

Browse files
committed
Working on improving SPEA2
1 parent c2dfad4 commit 7210b07

4 files changed

Lines changed: 27 additions & 21 deletions

File tree

examples/multiobjective/spea2/spea2_dtlz1.py renamed to examples/multiobjective/spea2/spea2_dtlz2.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from jmetal.algorithm.multiobjective.spea2 import SPEA2
22
from jmetal.operator.crossover import SBXCrossover
33
from jmetal.operator.mutation import PolynomialMutation
4-
from jmetal.problem import DTLZ2
4+
from jmetal.problem import DTLZ2, DTLZ1, DTLZ3
55
from jmetal.util.solution import (
66
print_function_values_to_file,
77
print_variables_to_file,
@@ -11,11 +11,11 @@
1111
if __name__ == "__main__":
1212
problem = DTLZ2()
1313

14-
max_evaluations = 20000
14+
max_evaluations = 30000
1515
algorithm = SPEA2(
1616
problem=problem,
17-
population_size=20,
18-
offspring_population_size=20,
17+
population_size=100,
18+
offspring_population_size=100,
1919
mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables(), distribution_index=20),
2020
crossover=SBXCrossover(probability=1.0, distribution_index=20),
2121
termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations),

examples/multiobjective/spea2/spea2_zdt1.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22
from jmetal.operator.crossover import SBXCrossover
33
from jmetal.operator.mutation import PolynomialMutation
44
from jmetal.problem import ZDT1
5+
from jmetal.algorithm.multiobjective.spea2 import SPEA2
56
from jmetal.util.solution import (
67
print_function_values_to_file,
78
print_variables_to_file,
89
)
910
from jmetal.util.termination_criterion import StoppingByEvaluations
1011

11-
if __name__ == "__main__":
12+
def main():
1213
problem = ZDT1()
1314

1415
max_evaluations = 20000
1516
algorithm = SPEA2(
1617
problem=problem,
17-
population_size=40,
18-
offspring_population_size=40,
18+
population_size=100,
19+
offspring_population_size=100,
1920
mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables(), distribution_index=20),
2021
crossover=SBXCrossover(probability=1.0, distribution_index=20),
2122
termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations),
@@ -31,3 +32,6 @@
3132
print(f"Algorithm: {algorithm.get_name()}")
3233
print(f"Problem: {problem.name()}")
3334
print(f"Computing time: {algorithm.total_computing_time}")
35+
36+
if __name__ == "__main__":
37+
main()

src/jmetal/algorithm/multiobjective/spea2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis
8080
ranking = StrengthRanking(self.dominance_comparator)
8181
density_estimator = KNearestNeighborDensityEstimator()
8282

83-
r = RankingAndDensityEstimatorReplacement(ranking, density_estimator, RemovalPolicyType.SEQUENTIAL)
84-
solutions = r.replace(population, offspring_population)
83+
replacement = RankingAndDensityEstimatorReplacement(ranking, density_estimator, RemovalPolicyType.SEQUENTIAL)
84+
solutions = replacement.replace(population, offspring_population)
8585

8686
return solutions
8787

src/jmetal/util/density_estimator.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
import numpy
66
from moocore import hv_contributions
7-
from scipy.spatial.distance import euclidean
7+
import numpy as np
8+
from scipy.spatial.distance import cdist
89

910
from jmetal.logger import get_logger
1011
from jmetal.util.comparator import Comparator, SolutionAttributeComparator
@@ -110,18 +111,19 @@ def compute_density_estimator(self, solutions: List[S]):
110111
if solutions_size <= self.k:
111112
return
112113

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+
120124
# 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
125127

126128
def sort(self, solutions: List[S]) -> List[S]:
127129
"""

0 commit comments

Comments
 (0)