Skip to content

Commit 35d211b

Browse files
committed
Sync the behavior as that in matlab: print errors if the original problem cause one
1 parent ae44310 commit 35d211b

1 file changed

Lines changed: 42 additions & 25 deletions

File tree

s2mpj_tools.py

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pandas as pd
55

66
from optiprofiler.opclasses import Problem
7+
from optiprofiler.utils import get_logger
78

89

910
def s2mpj_load(problem_name, *args):
@@ -63,7 +64,7 @@ def s2mpj_load(problem_name, *args):
6364
# Add the subfolder 'python_problems' under the 'src' directory to the system path.
6465
sys.path.insert(0, python_problems_dir)
6566
except Exception as err:
66-
print(f"Failed to add the path of Python problems of S2MPJ to the system path: {err}")
67+
get_logger(__name__).warning(f'Failed to add the path of Python problems of S2MPJ to the system path: {err}')
6768
raise
6869

6970
# Check if 'problem_name' has the pattern '_n_m' or '_n'. If it has, find the position of the pattern and return the dimension 'n' and the number of constraints 'm'.
@@ -143,8 +144,8 @@ def s2mpj_load(problem_name, *args):
143144
name = problem_name
144145

145146
fun = lambda x: _getfun(p, is_feasibility, name, x)
146-
grad = lambda x: _getgrad(p, is_feasibility, x)
147-
hess = lambda x: _gethess(p, is_feasibility, x)
147+
grad = lambda x: _getgrad(p, is_feasibility, name, x)
148+
hess = lambda x: _gethess(p, is_feasibility, name, x)
148149

149150
x0 = p.x0.flatten()
150151
xl = p.xlower.flatten()
@@ -183,7 +184,8 @@ def s2mpj_load(problem_name, *args):
183184
jx = jx.toarray()
184185
cx = cx.flatten()
185186
bx = jx @ x0 - cx
186-
except Exception:
187+
except Exception as err:
188+
_warn_s2mpj_evaluation_failure(name, 'the linear constraint Jacobian', err)
187189
jx = None
188190
bx = None
189191

@@ -221,13 +223,13 @@ def s2mpj_load(problem_name, *args):
221223
# -c(x)[idx_cge] + cl[idx_cge]] <= 0
222224
def ceq(x):
223225
if idx_ceq.size == 0: return None
224-
y = _getcx(p, x)
226+
y = _getcx(p, name, x)
225227
if y is None: return np.full(idx_ceq.size, np.nan)
226228
z = y[idx_ceq] - cu[idx_ceq]
227229
return np.full(idx_ceq.size, np.nan) if (hasattr(z, "size") and z.size == 0) else z
228230
def cub(x):
229231
if idx_cle.size == 0 and idx_cge.size == 0: return None
230-
y = _getcx(p, x)
232+
y = _getcx(p, name, x)
231233
if y is None: return np.full(idx_cle.size + idx_cge.size, np.nan)
232234
le = y[idx_cle] - cu[idx_cle] if idx_cle.size > 0 else None
233235
ge = y[idx_cge] - cl[idx_cge] if idx_cge.size > 0 else None
@@ -237,25 +239,25 @@ def cub(x):
237239
return np.concatenate([le, -ge])
238240
def hceq(x):
239241
if idx_ceq.size == 0: return []
240-
Hx = _getHx(p, x)
242+
Hx = _getHx(p, name, x)
241243
if Hx is None: return [np.full((x.size, x.size), np.nan)] * idx_ceq.size
242244
return [Hx[i] for i in idx_ceq]
243245
def hcub(x):
244246
if idx_cle.size == 0 and idx_cge.size == 0: return []
245-
Hx = _getHx(p, x)
247+
Hx = _getHx(p, name, x)
246248
if Hx is None: return [np.full((x.size, x.size), np.nan)] * (idx_cle.size + idx_cge.size)
247249
le = [Hx[i] for i in idx_cle] if idx_cle.size > 0 else []
248250
ge = [Hx[i] for i in idx_cge] if idx_cge.size > 0 else []
249251
return le + ge
250252

251253
def jceq(x):
252254
if idx_ceq.size == 0: return np.empty((0, p.n))
253-
Jx = _getJx(p, x)
255+
Jx = _getJx(p, name, x)
254256
if Jx is None: return np.full((idx_ceq.size, x.size), np.nan)
255257
return Jx[idx_ceq, :]
256258
def jcub(x):
257259
if idx_cle.size == 0 and idx_cge.size == 0: return np.empty((0, p.n))
258-
Jx = _getJx(p, x)
260+
Jx = _getJx(p, name, x)
259261
if Jx is None: return np.full((idx_cle.size + idx_cge.size, x.size), np.nan)
260262
le = Jx[idx_cle, :] if idx_cle.size > 0 else None
261263
ge = Jx[idx_cge, :] if idx_cge.size > 0 else None
@@ -568,11 +570,12 @@ def _getfun(p, is_feasibility, problem_name, x):
568570
f = p.fx(x)
569571
if hasattr(f, 'item'):
570572
f = f.item()
571-
except Exception:
573+
except Exception as err:
574+
_warn_s2mpj_evaluation_failure(problem_name, 'the objective function', err)
572575
f = np.nan
573576
return f
574577

575-
def _getgrad(p, is_feasibility, x):
578+
def _getgrad(p, is_feasibility, problem_name, x):
576579
if is_feasibility:
577580
g = np.zeros_like(x)
578581
else:
@@ -582,11 +585,12 @@ def _getgrad(p, is_feasibility, x):
582585
_, g = p.fgx(x)
583586
g = g.toarray() if hasattr(g, 'toarray') else g
584587
g = g.flatten()
585-
except Exception:
588+
except Exception as err:
589+
_warn_s2mpj_evaluation_failure(problem_name, 'the gradient of the objective function', err)
586590
g = np.full(x.size, np.nan)
587591
return g
588592

589-
def _gethess(p, is_feasibility, x):
593+
def _gethess(p, is_feasibility, problem_name, x):
590594
if is_feasibility:
591595
h = np.zeros((len(x), len(x)))
592596
else:
@@ -595,39 +599,52 @@ def _gethess(p, is_feasibility, x):
595599
try:
596600
_, _, h = p.fgHx(x)
597601
h = h.toarray() if hasattr(h, 'toarray') else h
598-
except Exception:
602+
except Exception as err:
603+
_warn_s2mpj_evaluation_failure(problem_name, 'the Hessian of the objective function', err)
599604
h = np.full((x.size, x.size), np.nan)
600605
return h
601606

602-
def _getcx(p, x):
607+
def _getcx(p, problem_name, x):
603608
buf = io.StringIO()
604609
with redirect_stdout(buf):
605610
try:
606611
c = p.cx(x)
607612
c = c.toarray() if hasattr(c, 'toarray') else c
608613
c = c.flatten()
609-
except Exception:
610-
c = None
614+
except Exception as err:
615+
_warn_s2mpj_evaluation_failure(problem_name, 'the nonlinear constraint function', err)
616+
c = np.full(getattr(p, 'm', 0), np.nan)
611617
return c
612618

613-
def _getJx(p, x):
619+
def _getJx(p, problem_name, x):
614620
buf = io.StringIO()
615621
with redirect_stdout(buf):
616622
try:
617623
_, j = p.cJx(x)[:2]
618624
j = j.toarray() if hasattr(j, 'toarray') else j
619-
except Exception:
620-
j = None
625+
except Exception as err:
626+
_warn_s2mpj_evaluation_failure(problem_name, 'the Jacobian of the nonlinear constraint function', err)
627+
j = np.full((getattr(p, 'm', 0), getattr(p, 'n', x.size)), np.nan)
621628
return j
622629

623-
def _getHx(p, x):
630+
def _getHx(p, problem_name, x):
624631
buf = io.StringIO()
625632
with redirect_stdout(buf):
626633
try:
627634
_, _, h = p.cJHx(x)
628635
for i in range(len(h)):
629636
if hasattr(h[i], 'toarray'):
630637
h[i] = h[i].toarray()
631-
except Exception:
632-
h = None
633-
return h
638+
except Exception as err:
639+
_warn_s2mpj_evaluation_failure(problem_name, 'the Hessian of the nonlinear constraint function', err)
640+
h = [np.full((getattr(p, 'n', x.size), getattr(p, 'n', x.size)), np.nan) for _ in range(getattr(p, 'm', 0))]
641+
return h
642+
643+
644+
def _warn_s2mpj_evaluation_failure(problem_name, what, err, max_len=180):
645+
logger = get_logger(__name__)
646+
msg = f'{type(err).__name__}: {err}'
647+
msg = re.sub(r'\s+', ' ', msg).strip()
648+
if len(msg) > max_len:
649+
msg = msg[:max_len - 3] + '...'
650+
logger.warning(f'Failed to evaluate {what} of S2MPJ problem {problem_name}: {msg}')

0 commit comments

Comments
 (0)