@@ -58,13 +58,11 @@ class AlgorithmBase:
5858 _work_model : WorkModelBase
5959 _logger : Logger
6060
61- def __init__ (self , work_model : WorkModelBase , parameters : dict , logger : Logger , rank_qoi : str , object_qoi : str ):
61+ def __init__ (self , work_model : WorkModelBase , parameters : dict , logger : Logger ):
6262 """Class constructor.
6363
6464 :param work_model: a WorkModelBase instance
6565 :param parameters: a dictionary of parameters
66- :param rank_qoi: rank QOI to track
67- :param object_qoi: object QOI to track.
6866 """
6967 # Assert that a logger instance was passed
7068 if not isinstance (logger , Logger ):
@@ -83,40 +81,18 @@ def __init__(self, work_model: WorkModelBase, parameters: dict, logger: Logger,
8381 self ._logger .error ("Could not create an algorithm without a dictionary of parameters" )
8482 raise SystemExit (1 )
8583
86- # Assert that quantity of interest names are string
87- if rank_qoi and not isinstance (rank_qoi , str ):
88- self ._logger .error ("Could not create an algorithm with non-string rank QOI name" )
89- raise SystemExit (1 )
90- self .__rank_qoi = rank_qoi
91- if object_qoi and not isinstance (object_qoi , str ):
92- self ._logger .error ("Could not create an algorithm with non-string object QOI name" )
93- raise SystemExit (1 )
94- self .__object_qoi = object_qoi
95- self ._logger .info (
96- f"Created base algorithm tracking rank { rank_qoi } and object { object_qoi } " )
97-
9884 # Initially no phase is assigned for processing
9985 self ._rebalanced_phase = None
10086
10187 # Save the initial communications data
10288 self ._initial_communications = {}
10389
104- # Map global statistical QOIs to their computation methods
90+ # Map rank statistics to their respective computation methods
10591 self .__statistics = {
10692 ("ranks" , lambda x : x .get_load ()): {
107- "minimum load" : "minimum" ,
108- "maximum load" : "maximum" ,
109- "load variance" : "variance" ,
110- "load imbalance" : "imbalance" },
111- ("largest_volumes" , lambda x : x ): {
112- "number of communication edges" : "cardinality" ,
113- "maximum largest directed volume" : "maximum" ,
114- "total largest directed volume" : "sum" },
115- ("ranks" , lambda x : self ._work_model .compute (x )): { #pylint:disable=W0108
116- "minimum work" : "minimum" ,
117- "maximum work" : "maximum" ,
118- "total work" : "sum" ,
119- "work variance" : "variance" }}
93+ "maximum load" : "maximum" },
94+ ("ranks" , lambda x : self ._work_model .compute (x )): {
95+ "total work" : "sum" }}
12096
12197 def get_rebalanced_phase (self ):
12298 """Return phased assigned for processing by algoritm."""
@@ -131,9 +107,7 @@ def factory(
131107 algorithm_name :str ,
132108 parameters : dict ,
133109 work_model : WorkModelBase ,
134- logger : Logger ,
135- rank_qoi : str ,
136- object_qoi :str ):
110+ logger : Logger ):
137111 """Instantiate the necessary concrete algorithm."""
138112 # Load up available algorithms
139113 # pylint:disable=W0641:possibly-unused-variable,C0415:import-outside-toplevel
@@ -148,90 +122,22 @@ def factory(
148122 try :
149123 # Instantiate and return object
150124 algorithm = locals ()[algorithm_name + "Algorithm" ]
151- return algorithm (work_model , parameters , logger , rank_qoi , object_qoi )
125+ return algorithm (work_model , parameters , logger )
152126 except Exception as e :
153127 # Otherwise, error out
154128 logger .error (f"Could not create an algorithm with name { algorithm_name } " )
155129 raise SystemExit (1 ) from e
156130
157- def _update_distributions_and_statistics (self , distributions : dict , statistics : dict ):
158- """Compute and update run distributions and statistics."""
159- # Create or update distributions of object quantities of interest
160- for object_qoi_name in tuple ({"load" , self .__object_qoi }):
161- if not object_qoi_name :
162- continue
163- try :
164- distributions .setdefault (f"object { object_qoi_name } " , []).append (
165- {o .get_id (): getattr (o , f"get_{ object_qoi_name } " )()
166- for o in self ._rebalanced_phase .get_objects ()})
167- except AttributeError as err :
168- self .__print_QOI ("obj" )
169- self ._logger .error (f"Invalid object_qoi name '{ object_qoi_name } '" )
170- raise SystemExit (1 ) from err
171-
172- # Create or update distributions of rank quantities of interest
173- for rank_qoi_name in tuple ({"objects" , "load" , self .__rank_qoi }):
174- if not rank_qoi_name or rank_qoi_name == "work" :
175- continue
176- try :
177- distributions .setdefault (f"rank { rank_qoi_name } " , []).append (
178- [getattr (p , f"get_{ rank_qoi_name } " )()
179- for p in self ._rebalanced_phase .get_ranks ()])
180- except AttributeError as err :
181- self .__print_QOI ("rank" )
182- self ._logger .error (f"Invalid rank_qoi name '{ rank_qoi_name } '" )
183- raise SystemExit (1 ) from err
184- distributions .setdefault ("rank work" , []).append (
185- [self ._work_model .compute (p ) for p in self ._rebalanced_phase .get_ranks ()])
186-
187- # Create or update distributions of edge quantities of interest
188- distributions .setdefault ("sent" , []).append (dict (
189- self ._rebalanced_phase .get_edge_maxima ().items ()))
190-
131+ def _update_statistics (self , statistics : dict ):
132+ """Compute and update run statistics."""
191133 # Create or update statistics dictionary entries
192134 for (support , getter ), stat_names in self .__statistics .items ():
193135 for k , v in stat_names .items ():
136+ self ._logger .debug (f"Updating { k } statistics for { support } " )
194137 stats = compute_function_statistics (
195138 getattr (self ._rebalanced_phase , f"get_{ support } " )(), getter )
196139 statistics .setdefault (k , []).append (getattr (stats , f"get_{ v } " )())
197140
198- def __print_QOI (self ,rank_or_obj ): # pylint:disable=invalid-name
199- """Print list of implemented QOI when invalid QOI is given."""
200- # Initialize file paths
201- current_path = os .path .abspath (__file__ )
202- target_dir = os .path .join (
203- os .path .dirname (os .path .dirname (current_path )), "Model" )
204- rank_script_name = "lbsRank.py"
205- object_script_name = "lbsObject.py"
206-
207- if rank_or_obj == "rank" :
208- # Create list of all Rank QOI (lbsRank.get_*)
209- r_qoi_list = ["work" ]
210- with open (os .path .join (target_dir , rank_script_name ), 'r' , encoding = "utf-8" ) as f :
211- lines = f .readlines ()
212- for line in lines :
213- if line [8 :12 ] == "get_" :
214- r_qoi_list .append (line [12 :line .find ("(" )])
215-
216- # Print QOI based on verbosity level
217- self ._logger .error ("List of all possible Rank QOI:" )
218- for r_qoi in r_qoi_list :
219- self ._logger .error ("\t " + r_qoi )
220-
221- if rank_or_obj == "obj" :
222- # Create list of all Object QOI (lbsObject.get_*)
223- o_qoi_list = []
224- with open (os .path .join (target_dir , object_script_name ), 'r' , encoding = "utf-8" ) as f :
225- lines = f .readlines ()
226- for line in lines :
227- if line [8 :12 ] == "get_" :
228- o_qoi_list .append (line [12 :line .find ("(" )])
229-
230- # Print QOI based on verbosity level
231- self ._logger .error ("List of all possible Object QOI:" )
232- for o_qoi in o_qoi_list :
233- self ._logger .error ("\t " + o_qoi )
234-
235141 def _report_final_mapping (self , logger ):
236142 """Report final rank object mapping in debug mode."""
237143 for rank in self ._rebalanced_phase .get_ranks ():
@@ -253,7 +159,7 @@ def _report_final_mapping(self, logger):
253159 logger .debug (
254160 f"object { k .get_id ()} on rank { k .get_rank_id ()} : { v } " )
255161
256- def _initialize (self , p_id , phases , distributions , statistics ):
162+ def _initialize (self , p_id , phases , statistics ):
257163 """Factor out pre-execution checks and initalizations."""
258164 # Ensure that a list with at least one phase was provided
259165 if not isinstance (phases , dict ) or not all (
@@ -286,16 +192,15 @@ def _initialize(self, p_id, phases, distributions, statistics):
286192 f"across { self ._rebalanced_phase .get_number_of_ranks ()} ranks "
287193 f"into phase { self ._rebalanced_phase .get_id ()} " )
288194
289- # Initialize run distributions and statistics
290- self ._update_distributions_and_statistics ( distributions , statistics )
195+ # Initialize run statistics
196+ self ._update_statistics ( statistics )
291197
292198 @abc .abstractmethod
293- def execute (self , p_id , phases , distributions , statistics , a_min_max ):
199+ def execute (self , p_id , phases , statistics , a_min_max ):
294200 """Execute balancing algorithm on Phase instance.
295201
296202 :param: p_id: index of phase to be rebalanced (all if equal to _)
297203 :param: phases: list of Phase instances
298- :param: distributions: dictionary of load-varying variables
299204 :param: statistics: dictionary of statistics
300205 :param: a_min_max: possibly empty list of optimal arrangements.
301206 """
0 commit comments