@@ -409,8 +409,10 @@ def get_flow_coverage(self) -> None:
409409
410410 self .flow_coverage [od_pair ] = {
411411 "flow_volume" : flow_volume ,
412- "covered_proportion" : covered_proportion ,
413- "covered_volume" : flow_volume * covered_proportion ,
412+ "covered_proportion" : round (covered_proportion , 2 ),
413+ "covered_volume" : round (
414+ flow_volume * covered_proportion , 2
415+ ),
414416 }
415417
416418 total_covered_volume = sum (
@@ -420,9 +422,9 @@ def get_flow_coverage(self) -> None:
420422 coverage ["flow_volume" ] for coverage in self .flow_coverage .values ()
421423 )
422424 return {
423- "covered_volume" : total_covered_volume ,
424- "flow_volume" : flow_volume ,
425- "covered_proportion" : total_covered_volume / flow_volume ,
425+ "covered_volume" : round ( total_covered_volume , 2 ) ,
426+ "flow_volume" : round ( flow_volume , 2 ) ,
427+ "covered_proportion" : round ( total_covered_volume / flow_volume , 2 ) ,
426428 }
427429
428430 def get_vmt_coverage (self ) -> Dict [str , float ]:
@@ -449,9 +451,7 @@ def get_vmt_coverage(self) -> Dict[str, float]:
449451
450452
451453class FRLMNodeCoverageMixin :
452-
453454 def calculate_covered_nodes (self ) -> None :
454-
455455 if self .threshold <= 0 :
456456 self .covered_nodes = []
457457 return
@@ -493,9 +493,7 @@ def get_node_coverage_percentage(self) -> float:
493493
494494
495495class FRLMSolverStatsMixin :
496-
497496 def extract_solver_statistics (self ) -> None :
498-
499497 if not hasattr (self , "model" ) or self .model is None :
500498 raise AttributeError ("Model must be solved first. Call solve()." )
501499
@@ -539,19 +537,23 @@ def get_detailed_results(self) -> Dict:
539537 if not hasattr (self , "solver_stats" ):
540538 self .extract_solver_statistics ()
541539
540+ model_params = {
541+ "vehicle_range" : round (self .vehicle_range , 2 ),
542+ "p_facilities" : self .p_facilities ,
543+ "capacity" : self .capacity ,
544+ "threshold" : self .threshold ,
545+ "objective_type" : self .objective ,
546+ }
547+
548+ if self .threshold > 0 :
549+ model_params ["weight" ] = self .weight
550+
542551 results = {
543- "model_parameters" : {
544- "vehicle_range" : self .vehicle_range ,
545- "p_facilities" : self .p_facilities ,
546- "capacity" : self .capacity ,
547- "threshold" : self .threshold ,
548- "weight" : self .weight ,
549- "objective_type" : self .objective ,
550- },
552+ "model_parameters" : model_params ,
551553 "solution" : {
552554 "status" : self .status ,
553555 "objective_value" : self .objective_value ,
554- "selected_facilities" : self .selected_facilities ,
556+ "selected_facilities" : list ( self .selected_facilities . keys ()) ,
555557 "solution_time" : self .solution_time ,
556558 },
557559 "solver_statistics" : self .solver_stats ,
@@ -1206,7 +1208,6 @@ def calculate_node_weights(self, include_destination: bool = False) -> np.ndarra
12061208 total_flow = sum (self .flows .values ())
12071209
12081210 for (origin , destination ), volume in self .flows .items ():
1209-
12101211 node_weights [origin ] += volume
12111212
12121213 if include_destination :
@@ -1337,7 +1338,7 @@ def solve(
13371338 Additional solver-specific parameters
13381339 """
13391340 if not self ._model_built :
1340- raise ValueError ( "Model must be built first." )
1341+ self . _build_model ( )
13411342
13421343 threshold = kwargs .get ("threshold" , self .threshold )
13431344 weight = kwargs .get ("weight" , self .weight )
@@ -1378,8 +1379,8 @@ def solve(
13781379
13791380 return {
13801381 "status" : self .status ,
1381- "objective_value" : self .objective_value ,
1382- "selected_facilities" : self .selected_facilities ,
1382+ "objective_value" : round ( self .objective_value ) ,
1383+ "selected_facilities" : list ( self .selected_facilities . keys ()) ,
13831384 }
13841385
13851386 def _solve_greedy (
@@ -1514,7 +1515,7 @@ def _solve_greedy(
15141515
15151516 self .objective_value = current_objective
15161517 # Final evaluation
1517- self .solution_time = time .time () - start_time
1518+ self .solution_time = round ( time .time () - start_time , 2 )
15181519 self .status = "Heuristic"
15191520 for k , site in enumerate (self .candidate_sites ):
15201521 self .facility_vars [k ].varValue = current_facilities .get (site , 0 )
@@ -1523,8 +1524,8 @@ def _solve_greedy(
15231524 result = {
15241525 "status" : self .status ,
15251526 "model_type" : "use ac_pc" if self .use_ac_pc else " use combination" ,
1526- "objective_value" : self .objective_value ,
1527- "selected_facilities" : self .selected_facilities ,
1527+ "objective_value" : round ( self .objective_value , 2 ) ,
1528+ "selected_facilities" : list ( self .selected_facilities . keys ()) ,
15281529 "objective_type" : objective ,
15291530 "flow_coverage" : self .flow_coverage ,
15301531 }
@@ -1903,7 +1904,7 @@ def _solve_pulp(
19031904 "No solver instance provided. Please specify a valid PuLP solver."
19041905 )
19051906
1906- self .solution_time = time .time () - start_time
1907+ self .solution_time = round ( time .time () - start_time , 2 )
19071908 self .pulp_status = self .model .status
19081909 self .status = pulp .LpStatus [self .model .status ]
19091910
@@ -1922,9 +1923,9 @@ def _solve_pulp(
19221923 result = {
19231924 "status" : self .status ,
19241925 "model_type" : "ac_pc" if self .use_ac_pc else "combination" ,
1925- "objective_value" : self .objective_value ,
1926- "selected_facilities" : self .selected_facilities , # Property will be called
1927- "solution_time" : self .solution_time ,
1926+ "objective_value" : round ( self .objective_value , 2 ) ,
1927+ "selected_facilities" : list ( self .selected_facilities . keys ()),
1928+ "solution_time" : round ( self .solution_time , 2 ) ,
19281929 "objective_type" : objective ,
19291930 }
19301931 return result
@@ -2013,7 +2014,6 @@ def _evaluate_capacitated_solution(self, facilities: Dict[Any, int]) -> Dict:
20132014 }
20142015
20152016 def _initialize_greedy_solution (self , method : str ) -> set :
2016-
20172017 supported_methods = ["empty" , "random" , "central" , "high_flow" ]
20182018
20192019 if method not in supported_methods :
@@ -2316,7 +2316,6 @@ def _estimate_facility_shadow_price(self) -> float:
23162316 return best_improvement
23172317
23182318 def get_shadow_prices (self ) -> Dict :
2319-
23202319 if self .solver_type == "pulp" :
23212320 shadow_prices = self .shadow_prices .copy ()
23222321 elif self .solver_type == "greedy" :
@@ -2504,8 +2503,9 @@ def __repr__(self):
25042503 f", capacity={ self .capacity } " if self .capacity is not None else ""
25052504 )
25062505 threshold_info = f", threshold={ self .threshold } " if self .threshold > 0 else ""
2506+ weight_info = f", weight={ self .weight } " if self .threshold > 0 else ""
25072507
25082508 return (
25092509 f"FRLM({ range_str } , p={ self .p_facilities } { capacity_info } "
2510- f"{ threshold_info } , weight= { self . weight } )"
2510+ f"{ threshold_info } { weight_info } )"
25112511 )
0 commit comments