@@ -63,7 +63,7 @@ def numerical_hessian_central(f, x, h=1e-3, ridge=1e-6):
6363 H = 0.5 * (H + H .T ) + ridge * np .eye (n )
6464 return H
6565
66- def build_proposal_from_hessian (H , tau_scale = 0.5 , min_eig = 1e-8 ):
66+ def build_proposal_from_hessian (H , tau_scale = 0.5 , min_eig = 1e-8 ):
6767 """
6868 Toma H ~ ∇²(-logpost)(MAP).
6969 Devuelve (cov_prop, chol_prop).
@@ -94,7 +94,34 @@ def build_proposal_from_hessian(H, tau_scale=0.5, min_eig=1e-8):
9494 cov_spd_j = cov_spd + jitter * np .eye (cov_spd .shape [0 ])
9595 L = np .linalg .cholesky (cov_spd_j )
9696
97- return cov_spd , L
97+ return cov_spd , L
98+
99+
100+ def build_proposal_from_covariance (cov , tau_scale = 0.5 , min_eig = 1e-8 ):
101+ cov = np .asarray (cov , dtype = float )
102+ cov = 0.5 * (cov + cov .T )
103+ cov_spd = make_spd_eig (tau_scale * cov , min_eig )
104+ try :
105+ L = np .linalg .cholesky (cov_spd )
106+ except np .linalg .LinAlgError :
107+ L = np .linalg .cholesky (cov_spd + 1e-6 * np .eye (cov_spd .shape [0 ]))
108+ return cov_spd , L
109+
110+
111+ def _optimizer_inverse_hessian (res , n_params : int ):
112+ hess_inv = getattr (res , "hess_inv" , None )
113+ if hess_inv is None :
114+ return None
115+ try :
116+ if hasattr (hess_inv , "todense" ):
117+ H_inv = np .asarray (hess_inv .todense (), dtype = float )
118+ else :
119+ H_inv = np .asarray (hess_inv , dtype = float )
120+ except Exception :
121+ return None
122+ if H_inv .shape != (n_params , n_params ) or not np .all (np .isfinite (H_inv )):
123+ return None
124+ return 0.5 * (H_inv + H_inv .T )
98125
99126
100127def run_map (
@@ -114,6 +141,7 @@ def run_map(
114141 method : str = "L-BFGS-B" ,
115142 hess_step : float = 1e-4 ,
116143 tau_scale : float = 0.5 ,
144+ hessian_strategy : str = "auto" ,
117145 include_jacobian_prior : bool = False , div = 0 ,
118146 likelihood_kwargs : Optional [Dict ] = None ):
119147
@@ -147,19 +175,41 @@ def f_obj(theta_work: np.ndarray):
147175 include_jacobian = include_jacobian_prior ,
148176 likelihood_kwargs = likelihood_kwargs )
149177
150- res = minimize (f_obj , theta0 , method = method , bounds = bounds )
151-
152- theta_map = np .asarray (res .x , dtype = float )
153- H = numerical_hessian_central (f_obj , theta_map , h = hess_step )
154- cov_prop , chol_prop = build_proposal_from_hessian (H , tau_scale = tau_scale , min_eig = 1e-8 )
178+ res = minimize (f_obj , theta0 , method = method , bounds = bounds )
179+
180+ theta_map = np .asarray (res .x , dtype = float )
181+ strategy = hessian_strategy .lower ()
182+ if strategy not in {"auto" , "optimizer" , "numerical" }:
183+ raise ValueError ("hessian_strategy debe ser 'auto', 'optimizer' o 'numerical'." )
184+
185+ H_inv_opt = None
186+ if strategy in {"auto" , "optimizer" }:
187+ H_inv_opt = _optimizer_inverse_hessian (res , theta_map .size )
188+
189+ if H_inv_opt is not None :
190+ cov_prop , chol_prop = build_proposal_from_covariance (
191+ H_inv_opt ,
192+ tau_scale = tau_scale ,
193+ min_eig = 1e-8 ,
194+ )
195+ try :
196+ H = np .linalg .pinv (H_inv_opt )
197+ except np .linalg .LinAlgError :
198+ H = np .eye (theta_map .size )
199+ hessian_source = "optimizer"
200+ else :
201+ H = numerical_hessian_central (f_obj , theta_map , h = hess_step )
202+ cov_prop , chol_prop = build_proposal_from_hessian (H , tau_scale = tau_scale , min_eig = 1e-8 )
203+ hessian_source = "numerical"
155204
156205
157206 return {
158207 "theta_map" : theta_map ,
159208 "neglogpost_map" : float (res .fun ),
160209 "success" : bool (res .success ),
161210 "message" : res .message ,
162- "nit" : res .nit ,
163- "hessian" : H ,
164- "cov_proposal" : cov_prop ,
211+ "nit" : res .nit ,
212+ "hessian" : H ,
213+ "hessian_source" : hessian_source ,
214+ "cov_proposal" : cov_prop ,
165215 "chol_proposal" : chol_prop }
0 commit comments