Skip to content

Commit 7672d99

Browse files
committed
Ldsda stops when neighbors are infeasible
1 parent 1bf8d4e commit 7672d99

1 file changed

Lines changed: 24 additions & 3 deletions

File tree

‎pyomo/contrib/gdpopt/ldsda.py‎

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)