@@ -70,12 +70,15 @@ def solve(self, model, **kwds):
7070 return super ().solve (model , ** kwds )
7171
7272 def _log_citation (self , config ):
73- config .logger .info ("\n " + """- LDSDA algorithm:
73+ config .logger .info (
74+ "\n "
75+ + """- LDSDA algorithm:
7476 Bernal DE, Ovalle D, Liñán DA, Ricardez-Sandoval LA, Gómez JM, Grossmann IE.
7577 Process Superstructure Optimization through Discrete Steepest Descent Optimization: a GDP Analysis and Applications in Process Intensification.
7678 Computer Aided Chemical Engineering 2022 Jan 1 (Vol. 49, pp. 1279-1284). Elsevier.
7779 https://doi.org/10.1016/B978-0-323-85159-6.50213-X
78- """ .strip ())
80+ """ .strip ()
81+ )
7982
8083 def _solve_gdp (self , model , config ):
8184 """
@@ -212,20 +215,32 @@ def neighbor_search(self, config):
212215 is_minimization = self .objective_sense != maximize
213216
214217 # Loop through all possible directions (neighbors)
218+ feasible_neighbors_count = 0
219+ evaluated_neighbors_count = 0
220+
215221 for direction in self .directions :
216222 # Generate a neighbor point by applying the direction to the current point
217223 neighbor = tuple (map (sum , zip (self .current_point , direction )))
218224
219225 # Check if the neighbor is valid
220226 if self ._check_valid_neighbor (neighbor ):
227+ evaluated_neighbors_count += 1
221228 # Solve the subproblem for this neighbor
222229 primal_improved , primal_bound = self ._solve_discrete_point (
223230 neighbor , SearchPhase .NEIGHBOR , config
224231 )
225232
226- if primal_bound is None :
233+ # Check feasibility using data manager (more reliable than simply checking primal_bound value)
234+ neighbor_info = self .data_manager .get_info (neighbor )
235+ is_feasible = False
236+ if neighbor_info is not None :
237+ is_feasible = neighbor_info .get ('feasible' , False )
238+
239+ if primal_bound is None or not is_feasible :
227240 continue
228241
242+ feasible_neighbors_count += 1
243+
229244 dist = sum ((x - y ) ** 2 for x , y in zip (neighbor , self .current_point ))
230245
231246 # NOTE: Neighbor selection must be independent of incumbent updates.
@@ -247,6 +262,12 @@ def neighbor_search(self, config):
247262 best_dist = dist
248263 locally_optimal = False
249264
265+ if evaluated_neighbors_count > 0 and feasible_neighbors_count == 0 :
266+ config .logger .info (
267+ "LDSDA stopping: All valid neighbors were found to be infeasible."
268+ )
269+ locally_optimal = True
270+
250271 # Move to the best neighbor if an improvement was found
251272 if not locally_optimal :
252273 self .current_point = best_neighbor
0 commit comments