1313except ImportError :
1414 print ("unable to import mpi4py" )
1515
16+ import time
17+
18+
1619# BnBNode
1720# corners of interval [l, u]
1821# upper and lower bounds of acquisition function
@@ -282,14 +285,14 @@ def __init__(self, acqf, options = {}):
282285 self .epsilon_prune = 1.e-14
283286 self .max_bnbiter = 2000
284287 self .nodes_per_batch = 1
285- # self.evaluator = MPIEvaluator(function_mode=False)
288+ self .max_bnbtime = 12 * 60 # 12 minutes
286289
287290 # Set options form command
288291 self .epsilon_gap = options .get ('epsilon_gap' , self .epsilon_gap )
289292 self .epsilon_diam = options .get ('epsilon_diam' , self .epsilon_diam )
290293 self .epsilon_prune = options .get ('epsilon_prune' , self .epsilon_prune )
291294 self .max_bnbiter = options .get ('max_iter' , self .max_bnbiter )
292- # self.evaluator = options.get('evaluator ', self.evaluator )
295+ self .max_bnbtime = options .get ('max_bnbtime ' , self .max_bnbtime )
293296 self .nodes_per_batch = options .get ('nodes_per_batch' , self .nodes_per_batch )
294297
295298 if is_running_with_mpi ():
@@ -315,7 +318,7 @@ def __init__(self, acqf, options = {}):
315318 self .bfsevaluator = MPIEvaluator (function_mode = False , max_workers = num_bfs_workers )
316319 self .num_bbs_workers = num_bbs_workers
317320 self .num_bfs_workers = num_bfs_workers
318- self .max_queue_size = 40 * self .num_bbs_workers
321+ self .max_queue_size = 10 * self .num_bbs_workers
319322
320323 # For minimization, we find a feasible function value as the upper bound on the minimum value of the acquisition function.
321324 def compute_acqf_upper_bound (self , l , u ):
@@ -440,25 +443,34 @@ def bnboptimize(self, l_init, u_init):
440443
441444 all_bfsnodes = []
442445
443- num_bbs_tasks_per_loop = np .zeros (10 , dtype = np .int32 )
444446
445447 # stopping criterion should be on the total maximum number of branched nodes
446- num_branches = 0
448+ self . num_branches = 0
447449
448450 initial_gap = self .best_node .aq_U - self .best_node .aq_L
449451
450- i_loop = 0
451- while num_branches < self .max_bnbiter :
452- i_loop += 1
452+ max_bbs_node_size = 0
453+ max_bfs_node_size = 0
454+ start_time = time .time ()
455+ while self .num_branches < self .max_bnbiter :
453456 # collect nodes to be branched on in list structure
454457 bbsnodes = []
455458 num_submitted_nodes = 0
456459
457- #if self.bbsevaluator.num_submitted_tasks() + self.bfsevaluator.num_submitted_tasks() > 200:
458- # continue
459-
460- if self .bbsevaluator .num_submitted_tasks () < 10 :
461- for i in range (self .nodes_per_batch - 1 ):
460+ # if the number of submitted jobs is too large then wait for some jobs to be processed
461+ if self .bbsevaluator .num_submitted_tasks () + self .bfsevaluator .num_submitted_tasks () > 10 * (self .num_bbs_workers + self .num_bfs_workers ):
462+ if time .time () - start_time > self .max_bnbtime :
463+ print ("maximum time has elapsed" )
464+ break
465+ else :
466+ print ("num submitted bbs tasks = " , self .bbsevaluator .num_submitted_tasks ())
467+ print ("num submitted bfs tasks = " , self .bfsevaluator .num_submitted_tasks ())
468+ time .sleep (1.0 ) # give time for Evaluators to process jobs
469+ continue
470+
471+ # only submit additional tasks if there aren't too many in the Evaluators queue
472+ if self .bbsevaluator .num_submitted_tasks () < 10 * self .num_bbs_workers :
473+ for i in range (self .nodes_per_batch ):
462474 if (not self .queue ):
463475 break # no more nodes available to send to evaluator for branching/bound computations
464476 _ , _ , node = heapq .heappop (self .queue )
@@ -471,8 +483,9 @@ def bnboptimize(self, l_init, u_init):
471483 self .bbsevaluator .submit_tasks (brancher .callback , bbsnodes )
472484
473485 bfsnodes = []
474- if self .bfsevaluator .num_submitted_tasks () < 10 :
475- for i in range (self .nodes_per_batch - 1 ):
486+ # only submit additional tasks if there aren't too many in the Evaluators queue
487+ if self .bfsevaluator .num_submitted_tasks () < 10 * self .num_bfs_workers :
488+ for i in range (self .nodes_per_batch ):
476489 if len (all_bfsnodes ) == 0 :
477490 break # no more nodes available to send to evaluator for branching/bound computations
478491 node = all_bfsnodes .pop (0 )
@@ -483,10 +496,6 @@ def bnboptimize(self, l_init, u_init):
483496 # asynchronously retrieve results from Evaluator that have been processed
484497 bbschildren = self .bbsevaluator .retrieve_results ()
485498
486- num_bbs_tasks_per_loop [i_loop % 10 ] = len (bbschildren )
487- #print("num bbs children evaluated = ", len(bbschildren))
488- #print("number of submitted bbs parents = ", num_submitted_nodes)
489-
490499 # not all children are return, hence children is a ragged array
491500 # need to flatten this ragged list
492501 bbschildren = [item for sublist in bbschildren for item in sublist ]
@@ -495,7 +504,7 @@ def bnboptimize(self, l_init, u_init):
495504 bfschildren = [item for sublist in bfschildren for item in sublist ]
496505
497506 children = bbschildren + bfschildren # join child lists
498- num_branches += len (children )
507+ self . num_branches += len (children )
499508 if len (children ) == 0 :
500509 continue
501510
@@ -520,11 +529,13 @@ def bnboptimize(self, l_init, u_init):
520529 heapq .heappush (self .queue , (child .aq_L , next (self ._ctr ), child ))
521530 else :
522531 all_bfsnodes .append (child )
532+ max_bbs_node_size = max (max_bbs_node_size , len (self .queue ))
533+ max_bfs_node_size = max (max_bfs_node_size , len (all_bfsnodes ))
523534
524535
525536 # BnB opt progress report
526537 gap = self .best_node .aq_U - self .best_node .aq_L
527- print (f"\n --- Total number branches { num_branches } ---" )
538+ print (f"\n --- Total number branches { self . num_branches } ---" )
528539 print (f"Best node bounds: l={ self .best_node .l } , u={ self .best_node .u } " )
529540 print (f"Node acquisition bounds: L={ self .best_node .aq_L } , U={ self .best_node .aq_U } " )
530541 print (f"Current best feasible value (LUB): { self .LUB } " )
@@ -539,12 +550,14 @@ def bnboptimize(self, l_init, u_init):
539550 all_bfsnodes = self ._prune_node_list (all_bfsnodes , self .LUB , self .epsilon_prune )
540551
541552 if updated_best_node :
542- if gap / initial_gap < self .epsilon_gap :
543- print (f"STOP: optimality gap = { gap / initial_gap } < { self .epsilon_gap } " )
553+ if gap < self .epsilon_gap :
554+ print (f"STOP: optimality gap = { gap } < { self .epsilon_gap } " )
544555 break
545556
546557 print ("\n === Optimization Finished ===" )
547- print (f"Total number of branches: { num_branches } " )
558+ print (f"Total number of branches: { self .num_branches } " )
559+ print (f"Max BBS node list size: { max_bbs_node_size } " )
560+ print (f"Max BFS node list size: { max_bfs_node_size } " )
548561 print (f"Best bounds: l={ self .best_node .l } , u={ self .best_node .u } " )
549562 print (f"Best feasible acquisition value (LUB): { self .LUB } " )
550563 print (f"Initial gap: { initial_gap } " )
0 commit comments