3232
3333from .stoppingCriteria import MaxNGen
3434from . import utils
35+ from . import hype
3536
3637logger = logging .getLogger ('__main__' )
3738
38- from deap .tools ._hypervolume import hv as hv_c
3939
40+ def get_hyped (pop ):
41+ # Cap the obj at 250
42+ points = numpy .array ([ind .fitness .values for ind in pop ])
43+ points [points > 250. ] = 250.
44+ lbounds = numpy .min (points , axis = 0 )
45+ ubounds = numpy .max (points , axis = 0 )
4046
41- def get_hv (to_evaluate ):
42- i = to_evaluate [0 ]
43- wobj = to_evaluate [1 ]
44- ref = to_evaluate [2 ]
45- return hv_c .hypervolume (numpy .concatenate ((wobj [:i ], wobj [i + 1 :])), ref )
47+ # Remove the dimensions that do not show any improvement
48+ to_remove = []
49+ for i , (lb , ub ) in enumerate (zip (lbounds , ubounds )):
50+ if lb >= 240 :
51+ to_remove .append (i )
52+ points = numpy .delete (points , to_remove , axis = 1 )
53+ lbounds = numpy .delete (lbounds , to_remove )
54+ ubounds = numpy .delete (ubounds , to_remove )
4655
56+ # Rescale the objective space
57+ points = (points - lbounds ) / numpy .max (ubounds .flatten ())
58+ ubounds = numpy .max (points , axis = 0 ) + 2.
4759
48- def contribution (to_evaluate ):
49- def _reduce_method (meth ):
50- """Overwrite reduce"""
51- return (getattr , (meth .__self__ , meth .__func__ .__name__ ))
52-
53- import copyreg
54- import types
55- copyreg .pickle (types .MethodType , _reduce_method )
56- import pebble
57-
58- with pebble .ProcessPool (max_tasks = 1 ) as pool :
59- tasks = pool .schedule (get_hv , kwargs = {'to_evaluate' : to_evaluate })
60- response = tasks .result ()
61-
62- return response
60+ hv = hype .hypeIndicatorSampled (points = points ,
61+ bounds = ubounds ,
62+ k = 5 ,
63+ nrOfSamples = 200000 )
64+ return hv
6365
6466
6567class CMA_MO (cma .StrategyMultiObjective ):
@@ -72,6 +74,7 @@ def __init__(self,
7274 max_ngen ,
7375 IndCreator ,
7476 RandIndCreator ,
77+ weight_hv = 0.5 ,
7578 map_function = None ,
7679 use_scoop = False ):
7780 """Constructor
@@ -105,6 +108,8 @@ def __init__(self,
105108
106109 self .population = []
107110 self .problem_size = len (starters [0 ])
111+
112+ self .weight_hv = weight_hv
108113
109114 self .map_function = map_function
110115 self .use_scoop = use_scoop
@@ -130,31 +135,6 @@ def __init__(self,
130135
131136 self .stopping_conditions = [MaxNGen (max_ngen )]
132137
133- def hyper_volume (self , front ):
134- """Compute the hypervolume contribution of each individual"""
135- wobj = numpy .array ([ind .fitness .values for ind in front ])
136- obj_ranges = (numpy .max (wobj , axis = 0 ) - numpy .min (wobj , axis = 0 ))
137- ref = numpy .max (wobj , axis = 0 ) + 1
138-
139- # Above 23 dimension, the hypervolume computation is too slow,
140- # we settle for the 23 dimension showing the largest range of values
141- max_ndim = 23
142- if len (ref ) > max_ndim :
143- idxs = list (range (len (ref )))
144- idxs = [idxs [k ] for k in numpy .argsort (obj_ranges )]
145- idxs = idxs [::- 1 ]
146- idxs = idxs [:max_ndim ]
147- wobj = wobj [:, idxs ]
148- ref = ref [idxs ]
149-
150- # Prepare the data and send it to multiprocess
151- to_evaluate = []
152- for i in range (len (front )):
153- to_evaluate .append ([i , numpy .copy (wobj ), numpy .copy (ref )])
154- contrib_values = self .map_function (contribution , to_evaluate )
155-
156- return list (contrib_values )
157-
158138 def _select (self , candidates ):
159139 """Select the best candidates of the population
160140
@@ -163,36 +143,60 @@ def _select(self, candidates):
163143 we rely on the hypervolume for this front. The remaining fronts are
164144 explicitly not chosen"""
165145
166- if len (candidates ) <= self .mu :
167- return candidates , []
168-
169- pareto_fronts = deap .tools .sortLogNondominated (candidates ,
170- len (candidates ))
171-
172- chosen = list ()
173- mid_front = None
174- not_chosen = list ()
175-
176- full = False
177- for front in pareto_fronts :
178- if len (chosen ) + len (front ) <= self .mu and not full :
179- chosen += front
180- elif mid_front is None and len (chosen ) < self .mu :
181- mid_front = front
182- # With this front, we selected enough individuals
183- full = True
184- else :
185- not_chosen += front
186-
187- # Hypervolume contribution to get the best candidates on the remaining
188- # front
189- k = self .mu - len (chosen )
190- if k > 0 :
191- hyperv = self .hyper_volume (mid_front )
192- _ = [mid_front [k ] for k in numpy .argsort (hyperv )]
193- chosen += _ [:k ]
194- not_chosen += _ [k :]
146+ #if len(candidates) <= self.mu:
147+ # return candidates, []
148+
149+ #pareto_fronts = deap.tools.sortLogNondominated(candidates,
150+ # len(candidates))
151+
152+ #chosen = list()
153+ #mid_front = None
154+ #not_chosen = list()
155+
156+ #full = False
157+ #for front in pareto_fronts:
158+ # if len(chosen) + len(front) <= self.mu and not full:
159+ # chosen += front
160+ # elif mid_front is None and len(chosen) < self.mu:
161+ # mid_front = front
162+ # # With this front, we selected enough individuals
163+ # full = True
164+ # else:
165+ # not_chosen += front
166+
167+ # HypE contribution to get the best candidates on the remaining front
168+ #k = self.mu - len(chosen)
169+ #if k > 0:
170+ # contribution = get_hyped(mid_front)
171+ # print(contribution)
172+ # idxs = numpy.argsort(contribution)
173+ # ordered_front = [mid_front[i] for i in idxs[::-1]]
174+ # chosen += ordered_front[:k]
175+ # not_chosen += ordered_front[k:]
176+
177+ if self .weight_hv == 0. :
178+ fit = [numpy .sum (ind .fitness .values ) for ind in candidates ]
179+ idx_fit = list (numpy .argsort (fit ))
180+ idx_scores = idx_fit [:]
181+
182+ elif self .weight_hv == 1. :
183+ hv = get_hyped (candidates )
184+ idx_hv = list (numpy .argsort (hv ))[::- 1 ]
185+ idx_scores = idx_hv [:]
195186
187+ else :
188+ hv = get_hyped (candidates )
189+ idx_hv = list (numpy .argsort (hv ))[::- 1 ]
190+ fit = [numpy .sum (ind .fitness .values ) for ind in candidates ]
191+ idx_fit = list (numpy .argsort (fit ))
192+ scores = []
193+ for i in range (len (candidates )):
194+ score = (self .weight_hv * idx_hv .index (i )) + ((1. - self .weight_hv ) * idx_fit .index (i ))
195+ scores .append (score )
196+ idx_scores = list (numpy .argsort (scores ))
197+
198+ chosen = [candidates [i ] for i in idx_scores [:self .mu ]]
199+ not_chosen = [candidates [i ] for i in idx_scores [self .mu :]]
196200 return chosen , not_chosen
197201
198202 def get_population (self , to_space ):
0 commit comments