@@ -45,13 +45,29 @@ def evaluate_coords(self, coeffs: Any, coords: np.ndarray) -> np.ndarray:
4545 """Evaluate approximation at continuous coordinate matrix of shape (N, d)."""
4646 pass
4747
48- def evaluate (self , coeffs : Any , qp : QualifiedPoint ) -> np .ndarray :
49- """Evaluate approximation at a single QualifiedPoint."""
50- coords = np .asarray (qp .val , dtype = float )
51- if coords .ndim == 1 :
52- res = self .evaluate_coords (coeffs , coords [None , :])
53- return res [0 ]
54- return self .evaluate_coords (coeffs , coords )
48+ def evaluate (self , coeffs : Any , * args ) -> np .ndarray :
49+ """Universal evaluation method for approximation schemes.
50+
51+ Supports:
52+ - `evaluate(coeffs, qp)`: single QualifiedPoint / QP
53+ - `evaluate(coeffs, batch)`: QualifiedBatch / SliceQP
54+ - `evaluate(coeffs, coords)`: coordinate array (N, d) or (d,)
55+ - `evaluate(coeffs, *args)`: multi-argument forms implemented by subclasses
56+ """
57+ if len (args ) == 1 :
58+ arg = args [0 ]
59+ if isinstance (arg , QualifiedBatch ):
60+ return self .evaluate_batch (coeffs , arg )
61+ if isinstance (arg , QualifiedPoint ):
62+ coords = np .asarray (arg .val , dtype = float )
63+ if coords .ndim == 1 :
64+ return self .evaluate_coords (coeffs , coords [None , :])[0 ]
65+ return self .evaluate_coords (coeffs , coords )
66+ coords = np .asarray (arg , dtype = float )
67+ if coords .ndim == 1 :
68+ return self .evaluate_coords (coeffs , coords [None , :])[0 ]
69+ return self .evaluate_coords (coeffs , coords )
70+ raise ValueError (f"Approximator.evaluate cannot handle { len (args )} arguments." )
5571
5672 def evaluate_batch (self , coeffs : Any , batch : QualifiedBatch ) -> np .ndarray :
5773 """Evaluate approximation over a QualifiedBatch / SliceQP."""
@@ -264,9 +280,55 @@ def evaluate_coords(self, coeffs: Any, coords: np.ndarray) -> np.ndarray:
264280 "Discrete exogenous states require regime index or QualifiedPoint for evaluation."
265281 )
266282
267- def evaluate (self , coeffs : Any , qp : QualifiedPoint ) -> np .ndarray :
283+ def evaluate (self , coeffs : Any , * args ) -> np .ndarray :
284+ """Universal evaluation on ProductApproximator.
285+
286+ Supports:
287+ - `evaluate(coeffs, qp)`: single QualifiedPoint / QP
288+ - `evaluate(coeffs, batch)`: QualifiedBatch / SliceQP
289+ - `evaluate(coeffs, s)`: continuous endogenous states alone (empty exo or single-regime)
290+ - `evaluate(coeffs, i, s)`: discrete regime index `i` + continuous states `s`
291+ - `evaluate(coeffs, m, s)`: continuous exogenous `m` + endogenous `s`
292+ """
293+ if len (args ) == 1 :
294+ arg = args [0 ]
295+ if isinstance (arg , QualifiedBatch ):
296+ return self .evaluate_batch (coeffs , arg )
297+ if isinstance (arg , QualifiedPoint ):
298+ return self ._evaluate_qp (coeffs , arg )
299+ # Coordinates array: continuous endogenous states alone
300+ return self .evaluate_s (coeffs , np .asarray (arg , dtype = float ))
301+
302+ elif len (args ) == 2 :
303+ a0 , a1 = args
304+ # Check for discrete regime index `i`
305+ if isinstance (a0 , (int , np .integer )):
306+ s_arr = np .asarray (a1 , dtype = float )
307+ if s_arr .ndim == 1 :
308+ return self .evaluate_regime (coeffs , int (a0 ), s_arr [None , :])[0 ]
309+ return self .evaluate_regime (coeffs , int (a0 ), s_arr )
310+
311+ a0_arr = np .asarray (a0 )
312+ a1_arr = np .asarray (a1 , dtype = float )
313+ if a0_arr .dtype .kind in ("i" , "u" ) and a0_arr .ndim == 0 :
314+ if a1_arr .ndim == 1 :
315+ return self .evaluate_regime (coeffs , int (a0_arr ), a1_arr [None , :])[0 ]
316+ return self .evaluate_regime (coeffs , int (a0_arr ), a1_arr )
317+
318+ # Continuous (m, s)
319+ if a0_arr .ndim == 1 and a1_arr .ndim == 1 :
320+ return self .evaluate_ms (coeffs , a0_arr [None , :], a1_arr [None , :])[0 ]
321+ return self .evaluate_ms (coeffs , a0_arr , a1_arr )
322+
323+ raise ValueError (
324+ f"ProductApproximator.evaluate cannot handle { len (args )} arguments."
325+ )
326+
327+ def _evaluate_qp (self , coeffs : Any , qp : QualifiedPoint ) -> np .ndarray :
268328 if self .is_empty_exo :
269329 coords = np .asarray (qp .val , dtype = float )
330+ if coords .ndim == 1 :
331+ return self .sub_approximator .evaluate_coords (coeffs , coords [None , :])[0 ]
270332 return self .sub_approximator .evaluate_coords (coeffs , coords )
271333 elif self .is_discrete_exo :
272334 i = qp .index
@@ -277,9 +339,12 @@ def evaluate(self, coeffs: Any, qp: QualifiedPoint) -> np.ndarray:
277339 )
278340 if isinstance (qp .loc , tuple ) and len (qp .loc ) >= 2 :
279341 endo_coords = qp .loc [1 ]
280- return self .sub_approximator .evaluate_coords (
281- coeffs [i ], np .asarray (endo_coords , dtype = float )
282- )
342+ c_arr = np .asarray (endo_coords , dtype = float )
343+ if c_arr .ndim == 1 :
344+ return self .sub_approximator .evaluate_coords (coeffs [i ], c_arr [None , :])[
345+ 0
346+ ]
347+ return self .sub_approximator .evaluate_coords (coeffs [i ], c_arr )
283348 elif self .is_cartesian_exo :
284349 return self .joint_approximator .evaluate (coeffs , qp )
285350 else :
0 commit comments