@@ -253,69 +253,101 @@ def initialise_coordinate_directions(self, number_of_samples, num_directions, pa
253
253
254
254
at_lower_boundary = (self .model .sl > - 0.01 * self .delta ) # sl = xl - x0, should be -ve, actually < -rhobeg
255
255
at_upper_boundary = (self .model .su < 0.01 * self .delta ) # su = xu - x0, should be +ve, actually > rhobeg
256
-
257
- xpts_added = np .zeros ((num_directions + 1 , self .n ()))
258
- for k in range (1 , num_directions + 1 ):
259
- # k = 0 --> base point (xpt = 0) [ not here]
260
- # k = 1, ..., 2n --> coordinate directions [1,...,n and n+1,...,2n]
261
- # k = 2n+1, ..., (n+1)(n+2)/2 --> off-diagonal directions
262
- if 1 <= k < self .n () + 1 : # first step along coord directions
256
+
257
+ if params ("init.run_in_parallel" ) and num_directions <= self .n ():
258
+ # Can do all the evaluation in parallel if <= n+1 interpolation points, but if larger
259
+ # then the step depends on the function value at previous steps and does point swapping
260
+ xpts_added = np .zeros ((num_directions + 1 , self .n ()))
261
+ eval_obj_results = []
262
+ for k in range (1 , num_directions + 1 ): # k = 1, ..., num_directions
263
+ # always have k = 1, ..., n since num_directions <= n
263
264
dirn = k - 1 # direction to move in (0,...,n-1)
264
265
stepa = self .delta if not at_upper_boundary [dirn ] else - self .delta # take a +delta step if at lower, -delta if at upper
265
266
stepb = None
266
267
xpts_added [k , dirn ] = stepa # set new (relative) point to the step since we haven't done any moving, so relative point is all zeros.
268
+
269
+ # Evaluate objective at this new point
270
+ x = self .model .as_absolute_coordinates (xpts_added [k , :])
271
+ eval_obj_results .append (self .evaluate_objective (x , number_of_samples , params ))
272
+
273
+ # Evaluations done, now add to the model
274
+ for k in range (1 , num_directions + 1 ):
275
+ x = self .model .as_absolute_coordinates (xpts_added [k , :])
276
+ rvec_list , obj_list , num_samples_run , exit_info = eval_obj_results [k - 1 ]
277
+ # Handle exit conditions (f < min obj value or maxfun reached)
278
+ if exit_info is not None :
279
+ if num_samples_run > 0 :
280
+ self .model .save_point (x , np .mean (rvec_list [:num_samples_run , :], axis = 0 ), num_samples_run , self .nx ,
281
+ x_in_abs_coords = True )
282
+ return exit_info # return & quit
267
283
268
- elif self .n () + 1 <= k < 2 * self .n () + 1 : # second step along coord directions
269
- dirn = k - self .n () - 1 # direction to move in (0,...,n-1)
270
- stepa = xpts_added [k - self .n (), dirn ] # previous step
271
- stepb = - self .delta # new step
272
- if at_lower_boundary [dirn ]:
273
- # if at lower boundary, set the second step to be +ve
274
- stepb = min (2.0 * self .delta , self .model .su [dirn ]) # su = xu - x0, should be +ve
275
- if at_upper_boundary [dirn ]:
276
- # if at upper boundary, set the second step to be -ve
277
- stepb = max (- 2.0 * self .delta , self .model .sl [dirn ]) # sl = xl - x0, should be -ve
278
- xpts_added [k , dirn ] = stepb
279
-
280
- else : # k = 2n+1, ..., (n+1)(n+2)/2
281
- # p = (k - 1) % n + 1 # cycles through (1,...,n), starting at 2n+1 --> 1
282
- # l = (k - 2 * n - 1) / n + 1 # (1,...,1, 2, ..., 2, etc.) where each number appears n times
283
- # q = (p + l if p + l <= n else p + l - n)
284
- stepa = None
285
- stepb = None
286
- itemp = (k - self .n () - 1 ) // self .n ()
287
- q = k - itemp * self .n () - self .n ()
288
- p = q + itemp
289
- if p > self .n ():
290
- p , q = q , p - self .n () # does swap correctly in Python
291
-
292
- xpts_added [k , p - 1 ] = xpts_added [p , p - 1 ]
293
- xpts_added [k , q - 1 ] = xpts_added [q , q - 1 ]
284
+ # Otherwise, add new results (increments model.npt_so_far)
285
+ self .model .change_point (k , x - self .model .xbase , rvec_list [0 , :], self .nx ) # expect step, not absolute x
286
+ for i in range (1 , num_samples_run ):
287
+ self .model .add_new_sample (k , rvec_extra = rvec_list [i , :])
288
+ else :
289
+ xpts_added = np .zeros ((num_directions + 1 , self .n ()))
290
+ for k in range (1 , num_directions + 1 ):
291
+ # k = 0 --> base point (xpt = 0) [ not here]
292
+ # k = 1, ..., 2n --> coordinate directions [1,...,n and n+1,...,2n]
293
+ # k = 2n+1, ..., (n+1)(n+2)/2 --> off-diagonal directions
294
+ if 1 <= k < self .n () + 1 : # first step along coord directions
295
+ dirn = k - 1 # direction to move in (0,...,n-1)
296
+ stepa = self .delta if not at_upper_boundary [dirn ] else - self .delta # take a +delta step if at lower, -delta if at upper
297
+ stepb = None
298
+ xpts_added [k , dirn ] = stepa # set new (relative) point to the step since we haven't done any moving, so relative point is all zeros.
299
+
300
+ elif self .n () + 1 <= k < 2 * self .n () + 1 : # second step along coord directions
301
+ dirn = k - self .n () - 1 # direction to move in (0,...,n-1)
302
+ stepa = xpts_added [k - self .n (), dirn ] # previous step
303
+ stepb = - self .delta # new step
304
+ if at_lower_boundary [dirn ]:
305
+ # if at lower boundary, set the second step to be +ve
306
+ stepb = min (2.0 * self .delta , self .model .su [dirn ]) # su = xu - x0, should be +ve
307
+ if at_upper_boundary [dirn ]:
308
+ # if at upper boundary, set the second step to be -ve
309
+ stepb = max (- 2.0 * self .delta , self .model .sl [dirn ]) # sl = xl - x0, should be -ve
310
+ xpts_added [k , dirn ] = stepb
311
+
312
+ else : # k = 2n+1, ..., (n+1)(n+2)/2
313
+ # p = (k - 1) % n + 1 # cycles through (1,...,n), starting at 2n+1 --> 1
314
+ # l = (k - 2 * n - 1) / n + 1 # (1,...,1, 2, ..., 2, etc.) where each number appears n times
315
+ # q = (p + l if p + l <= n else p + l - n)
316
+ stepa = None
317
+ stepb = None
318
+ itemp = (k - self .n () - 1 ) // self .n ()
319
+ q = k - itemp * self .n () - self .n ()
320
+ p = q + itemp
321
+ if p > self .n ():
322
+ p , q = q , p - self .n () # does swap correctly in Python
323
+
324
+ xpts_added [k , p - 1 ] = xpts_added [p , p - 1 ]
325
+ xpts_added [k , q - 1 ] = xpts_added [q , q - 1 ]
294
326
295
- # Evaluate objective at this new point
296
- x = self .model .as_absolute_coordinates (xpts_added [k , :])
297
- rvec_list , obj_list , num_samples_run , exit_info = self .evaluate_objective (x , number_of_samples , params )
327
+ # Evaluate objective at this new point
328
+ x = self .model .as_absolute_coordinates (xpts_added [k , :])
329
+ rvec_list , obj_list , num_samples_run , exit_info = self .evaluate_objective (x , number_of_samples , params )
298
330
299
- # Handle exit conditions (f < min obj value or maxfun reached)
300
- if exit_info is not None :
301
- if num_samples_run > 0 :
302
- self .model .save_point (x , np .mean (rvec_list [:num_samples_run , :], axis = 0 ), num_samples_run , self .nx ,
303
- x_in_abs_coords = True )
304
- return exit_info # return & quit
331
+ # Handle exit conditions (f < min obj value or maxfun reached)
332
+ if exit_info is not None :
333
+ if num_samples_run > 0 :
334
+ self .model .save_point (x , np .mean (rvec_list [:num_samples_run , :], axis = 0 ), num_samples_run , self .nx ,
335
+ x_in_abs_coords = True )
336
+ return exit_info # return & quit
305
337
306
- # Otherwise, add new results (increments model.npt_so_far)
307
- self .model .change_point (k , x - self .model .xbase , rvec_list [0 , :], self .nx ) # expect step, not absolute x
308
- for i in range (1 , num_samples_run ):
309
- self .model .add_new_sample (k , rvec_extra = rvec_list [i , :])
310
-
311
- # If k exceeds N+1, then the positions of the k-th and (k-N)-th interpolation
312
- # points may be switched, in order that the function value at the first of them
313
- # contributes to the off-diagonal second derivative terms of the initial quadratic model.
314
- # Note: this works because the steps for (k) and (k-n) points were in the same coordinate direction
315
- if self .n () + 1 <= k < 2 * self .n () + 1 :
316
- # Only swap if steps were in different directions AND new pt has lower objective
317
- if stepa * stepb < 0.0 and self .model .objval [k ] < self .model .objval [k - self .n ()]:
318
- xpts_added [[k , k - self .n ()]] = xpts_added [[k - self .n (), k ]]
338
+ # Otherwise, add new results (increments model.npt_so_far)
339
+ self .model .change_point (k , x - self .model .xbase , rvec_list [0 , :], self .nx ) # expect step, not absolute x
340
+ for i in range (1 , num_samples_run ):
341
+ self .model .add_new_sample (k , rvec_extra = rvec_list [i , :])
342
+
343
+ # If k exceeds N+1, then the positions of the k-th and (k-N)-th interpolation
344
+ # points may be switched, in order that the function value at the first of them
345
+ # contributes to the off-diagonal second derivative terms of the initial quadratic model.
346
+ # Note: this works because the steps for (k) and (k-n) points were in the same coordinate direction
347
+ if self .n () + 1 <= k < 2 * self .n () + 1 :
348
+ # Only swap if steps were in different directions AND new pt has lower objective
349
+ if stepa * stepb < 0.0 and self .model .objval [k ] < self .model .objval [k - self .n ()]:
350
+ xpts_added [[k , k - self .n ()]] = xpts_added [[k - self .n (), k ]]
319
351
320
352
return None # return & continue
321
353
0 commit comments