@@ -1931,16 +1931,7 @@ def _probe(n: int) -> bool:
19311931 return ok
19321932
19331933 space = list (range (n_min , len (consumer_indices ) + 1 ))
1934- while len (space ) >= 5 :
1935- mid = space [len (space ) // 2 ]
1936- if _probe (mid ):
1937- space = [x for x in space if x <= mid ]
1938- else :
1939- space = [x for x in space if x > mid ]
1940- for n in space :
1941- if n == space [- 1 ] or _probe (n ):
1942- return n
1943- return n_min
1934+ return self ._binary_search_n (space , _probe )
19441935
19451936 def _place_poles_with_roads (self ):
19461937 """
@@ -1958,6 +1949,25 @@ def _place_poles_with_roads(self):
19581949 n_kmeans = self ._find_opt_kmeans_for_unassigned (unassigned )
19591950 self .kmeans_clustering (n_clusters = n_kmeans , consumer_indices = unassigned )
19601951
1952+ @staticmethod
1953+ def _binary_search_n (space : list , probe ) -> int :
1954+ """Binary-search the minimum n in space that satisfies probe(n).
1955+
1956+ Narrows with median pivot until fewer than 5 candidates remain,
1957+ then scans linearly. Returns first satisfying n, or the last
1958+ element as a guaranteed fallback.
1959+ """
1960+ while len (space ) >= 5 :
1961+ mid = space [len (space ) // 2 ]
1962+ if probe (mid ):
1963+ space = [x for x in space if x <= mid ]
1964+ else :
1965+ space = [x for x in space if x > mid ]
1966+ for n in space :
1967+ if n == space [- 1 ] or probe (n ):
1968+ return n
1969+ return space [0 ]
1970+
19611971 def is_enough_poles (self , n ):
19621972 self ._clear_poles ()
19631973 self .kmeans_clustering (n_clusters = n )
@@ -1969,31 +1979,13 @@ def is_enough_poles(self, n):
19691979 return not constraints_violation .shape [0 ] > 0
19701980
19711981 def _find_opt_number_of_poles (self , n_mg_consumers ):
1972- # calculate the minimum number of poles based on the
1973- # maximum number of connections at each pole
1974- if self .pole_max_connection == 0 :
1975- min_number_of_poles = 1
1976- else :
1977- min_number_of_poles = int (
1978- np .ceil (n_mg_consumers / self .pole_max_connection ),
1979- )
1980-
1981- space = pd .Series (range (min_number_of_poles , n_mg_consumers , 1 ))
1982-
1983- for _ in range (min_number_of_poles , n_mg_consumers , 1 ):
1984- median_search_threshold = 5
1985- if len (space ) >= median_search_threshold :
1986- next_n = int (space .median ())
1987- if self .is_enough_poles (next_n ) is True :
1988- space = space [space <= next_n ]
1989- else :
1990- space = space [space > next_n ]
1991- else :
1992- for next_n in space :
1993- if next_n == space .iloc [- 1 ] or self .is_enough_poles (next_n ) is True :
1994- return next_n
1995-
1996-
1982+ min_number_of_poles = (
1983+ int (np .ceil (n_mg_consumers / self .pole_max_connection ))
1984+ if self .pole_max_connection > 0
1985+ else 1
1986+ )
1987+ space = list (range (min_number_of_poles , n_mg_consumers ))
1988+ return self ._binary_search_n (space , self .is_enough_poles )
19971989
19981990
19991991
0 commit comments