44import pandas as pd
55
66from optiprofiler .opclasses import Problem
7+ from optiprofiler .utils import get_logger
78
89
910def 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