@@ -30,6 +30,17 @@ class Neighborhood:
3030 a 'home' coordinate
3131 """
3232
33+ # This defines the bounds of how the vector calculated from
34+ # measurements is converted to a step vector.
35+ #
36+ # The translation will return the lowest index that has a value greater
37+ # than the input value.
38+ #
39+ # For example, if the input is greater than the value in index 1 but less than
40+ # the value in index 2, the resulting step will be 1
41+ #
42+ TRANSLATION_LIST = [0.09 , 0.3 , 1.0 ]
43+
3344 def __init__ (self , neighborhood_config : NeighborhoodConfig ,
3445 home_coordinate : Coordinate ):
3546 """
@@ -90,26 +101,14 @@ def force_slow_mode(self):
90101 """
91102 self ._force_slow_mode = True
92103
93- def calculate_new_coordinate (self ,
94- magnitude : int ,
95- enable_clipping : bool = True ,
96- clip_value : int = 2 ) -> Coordinate :
104+ def determine_new_home (self ) -> Coordinate :
97105 """
98106 Based on the measurements in the neighborhood, determine where
99107 the next location should be.
100108
101109 If the neighborhood is in slow mode, return the best found measurement
102110 Otherwise calculate a new coordinate from the measurements
103111
104- Parameters
105- ----------
106- magnitude
107- How large of a step to take
108- enable_clipping
109- Determines whether or not to clip the final step vector.
110- clip_value
111- What value to clip the vector at, if it is enabled
112-
113112 Returns
114113 -------
115114 new_coordinate
@@ -119,8 +118,7 @@ def calculate_new_coordinate(self,
119118 if self ._is_slow_mode ():
120119 return self ._get_best_coordinate_found ()
121120 else :
122- return self ._calculate_new_coordinate (magnitude , enable_clipping ,
123- clip_value )
121+ return self ._calculate_new_home ()
124122
125123 def _get_best_coordinate_found (self ) -> Coordinate :
126124 vectors , measurements = self ._get_measurements_passing_constraints ()
@@ -139,48 +137,31 @@ def _get_best_coordinate_found(self) -> Coordinate:
139137 best_coordinate = self ._home_coordinate + best_vector
140138 return best_coordinate
141139
142- def _calculate_new_coordinate (self , magnitude , enable_clipping ,
143- clip_value ) -> Coordinate :
144-
145- step_vector = self ._get_step_vector () * magnitude
146-
147- if enable_clipping :
148- step_vector = self ._clip_vector_values (vector = step_vector ,
149- clip_value = clip_value )
150- step_vector .round ()
151-
140+ def _calculate_new_home (self ) -> Coordinate :
141+ step_vector = self ._get_step_vector ()
142+ step_vector = self ._translate_step_vector (step_vector ,
143+ Neighborhood .TRANSLATION_LIST )
152144 tmp_new_coordinate = self ._home_coordinate + step_vector
153145 new_coordinate = self ._clamp_coordinate_to_bounds (tmp_new_coordinate )
154146 return new_coordinate
155147
156- def _clip_vector_values (self , vector : Coordinate ,
157- clip_value : int ) -> Coordinate :
158- """
159- Clip the values of the vector to be within the range of
160- [-clip_value, clip_value]. The clipping preserves the direction
161- of the vector (e.g. if the clip_value is 2, then [10, 5] will be
162- clipped to [2, 1] instead of [2, 2]).
163-
164- Parameters
165- ----------
166- vector
167- an input vector that may require clipping
168- clip_value
169- a non-negative integer that bounds the values of the input vector
148+ def _translate_step_vector (self , step_vector : Coordinate ,
149+ translate_list : List [float ]):
170150
171- Returns
172- -------
173- vector
174- a vector with all of its values within [-clip_value, clip_value]
175- """
176- assert clip_value >= 0 , "clip_value must be non-negative number."
151+ for i , v in enumerate (step_vector ):
152+ step_vector [i ] = self ._translate_value (v , translate_list )
177153
178- max_value = max ( abs ( c ) for c in vector )
154+ return step_vector
179155
180- if max_value > clip_value and max_value != 0 :
181- for i in range (len (vector )):
182- vector [i ] = clip_value * vector [i ] / max_value
183- return vector
156+ def _translate_value (self , value : float ,
157+ translation_list : List [float ]) -> int :
158+ ret = 0
159+ for index , bound in enumerate (translation_list ):
160+ if value > 0 and value > bound :
161+ ret = index + 1
162+ if value < 0 and value < - 1 * bound :
163+ ret = - 1 * (index + 1 )
164+ return ret
184165
185166 def pick_coordinate_to_initialize (self ) -> Optional [Coordinate ]:
186167 """
@@ -272,8 +253,7 @@ def _enumerate_all_values_in_bounds(
272253 self , bounds : List [List [int ]]) -> List [List [int ]]:
273254 possible_index_values = []
274255 for bound in bounds :
275- possible_index_values .append (list (range (bound [0 ], bound [1 ])))
276-
256+ possible_index_values .append (list (range (bound [0 ], bound [1 ] + 1 )))
277257 tuples = list (product (* possible_index_values ))
278258 return [list (x ) for x in tuples ]
279259
@@ -302,95 +282,62 @@ def _get_step_vector(self) -> Coordinate:
302282 Calculate a vector that indicates a direction to step from the
303283 home coordinate (current center).
304284
305- If the home coordinate is passing the constraints, the method
306- calculates the step vector based on the objectives given.
307- Otherwise, it calculates the step vector based on the constraints
308- so that it steps toward the region that passes the constraints.
309-
310285 Returns
311286 -------
312287 step_vector
313288 a coordinate that tells the direction to move.
314289 """
315- home_measurement = self ._get_home_measurement ()
316290
317- assert home_measurement is not None , "Home measurement cannot be NoneType."
291+ compare_constraints = not self ._is_home_passing_constraints ()
292+ return self ._calculate_step_vector_from_measurements (
293+ compare_constraints = compare_constraints )
318294
319- if self . _is_home_passing_constraints ():
320- return self . _optimize_for_objectives ( home_measurement )
295+ def _calculate_step_vector_from_measurements (
296+ self , compare_constraints : bool ) -> Coordinate :
321297
322- return self ._optimize_for_constraints (home_measurement )
323-
324- def _optimize_for_objectives (
325- self , home_measurement : RunConfigMeasurement ) -> Coordinate :
326- """
327- Calculate a step vector that maximizes the current objectives.
328- If no vectors are provided, return zero vector.
329-
330- Parameters
331- ----------
332- vectors
333- list of vectors from home coordinate to the neighboring
334- coordinates that are passing constraints
335- measurements
336- list of measurements of the neighboring coordinates that
337- are passing constraints
298+ home_measurement = self ._get_home_measurement ()
299+ vectors , measurements = self ._get_all_visited_measurements ()
338300
339- Returns
340- -------
341- step_vector
342- a coordinate that tells the direction to move.
343- """
344- vectors , measurements = self ._get_measurements_passing_constraints ()
345- step_vector = Coordinate ([0 ] * self ._config .get_num_dimensions ())
301+ # This function should only ever be called if all are passing or none are passing
302+ _ , p = self ._get_measurements_passing_constraints ()
303+ assert (len (p ) == 0 or len (p ) == len (measurements ))
346304
347305 if not vectors :
348- return step_vector
349-
350- for vector , measurement in zip (vectors , measurements ):
351- weight = home_measurement .compare_measurements (measurement )
352- step_vector += vector * weight
353-
354- step_vector /= len (vectors )
355- return step_vector
306+ return Coordinate ([0 ] * self ._config .get_num_dimensions ())
356307
357- def _optimize_for_constraints (
358- self , home_measurement : RunConfigMeasurement ) -> Coordinate :
359- """
360- Calculate a step vector that steps toward the coordinates that
361- pass the constraints (set default weights to 1.0). When no vectors
362- are provided (meaning there are no neighbors passing constraints),
363- continue with the neighbors that are not passing constraints by
364- comparing how much they are close to passing constraints.
308+ weights = []
309+ for m in measurements :
310+ if compare_constraints :
311+ weight = home_measurement .compare_constraints (m )
312+ else :
313+ weight = home_measurement .compare_measurements (m )
314+ weights .append (weight )
365315
366- Parameters
367- ----------
368- vectors
369- list of vectors from home coordinate to the neighboring
370- coordinates that are passing constraints
371- measurements
372- list of measurements of the neighboring coordinates that
373- are passing constraints
316+ return self ._calculate_step_vector_from_vectors_and_weights (
317+ vectors , weights )
374318
375- Returns
376- -------
377- step_vector
378- a coordinate that tells the direction to move.
379- """
380- vectors , measurements = self ._get_measurements_passing_constraints ()
319+ def _calculate_step_vector_from_vectors_and_weights (self , vectors , weights ):
381320 step_vector = Coordinate ([0 ] * self ._config .get_num_dimensions ())
321+ dim_sum_vector = Coordinate ([0 ] * self ._config .get_num_dimensions ())
322+
323+ # For each dimension -
324+ # if non zero, add weight (inverting if dimension is negative)
325+ # divide by sum of coordinate of that dimension
326+ for vector , weight in zip (vectors , weights ):
327+
328+ for dim , v in enumerate (vector ):
329+ if v :
330+ if v > 0 :
331+ step_vector [dim ] += weight
332+ dim_sum_vector [dim ] += v
333+ else :
334+ step_vector [dim ] -= weight
335+ dim_sum_vector [dim ] -= v
336+
337+ for dim , v in enumerate (dim_sum_vector ):
338+ if v :
339+ step_vector [dim ] /= v
382340
383- if not vectors :
384- vectors , measurements = self ._get_all_visited_measurements ()
385-
386- for vector , measurement in zip (vectors , measurements ):
387- weight = home_measurement .compare_constraints (measurement )
388- if measurement .is_passing_constraints ():
389- weight = 1.0 # when home fails & neighbor passes
390-
391- step_vector += vector * weight
392-
393- step_vector /= len (vectors )
394341 return step_vector
395342
396343 def _get_all_visited_measurements (
@@ -405,7 +352,6 @@ def _get_all_visited_measurements(
405352 collection of vectors and their measurements.
406353 """
407354 visited_coordinates = self ._get_visited_coordinates ()
408-
409355 vectors = []
410356 measurements = []
411357 for coordinate in visited_coordinates :
0 commit comments