1717import math
1818import time
1919import warnings
20- from typing import Callable , Union , Dict , Sequence , Tuple
20+ from typing import Callable , Union , Dict , Sequence , Tuple , Optional , Any , cast
2121
2222import jax
2323import jax .numpy as jnp
@@ -124,21 +124,21 @@ class SlowPointFinder(base.DSAnalyzer):
124124 def __init__ (
125125 self ,
126126 f_cell : Union [Callable , DynamicalSystem ],
127- f_type : str = None ,
128- f_loss : Callable = None ,
127+ f_type : Optional [ str ] = None ,
128+ f_loss : Optional [ Callable ] = None ,
129129 verbose : bool = True ,
130130 args : Tuple = (),
131131
132132 # parameters for `f_cell` is DynamicalSystem instance
133- inputs : Sequence = None ,
134- t : float = None ,
135- dt : float = None ,
136- target_vars : Dict [str , bm .Variable ] = None ,
137- excluded_vars : Union [Sequence [bm .Variable ], Dict [str , bm .Variable ]] = None ,
133+ inputs : Optional [ Sequence ] = None ,
134+ t : Optional [ float ] = None ,
135+ dt : Optional [ float ] = None ,
136+ target_vars : Optional [ Dict [str , bm .Variable ] ] = None ,
137+ excluded_vars : Optional [ Union [Sequence [bm .Variable ], Dict [str , bm .Variable ] ]] = None ,
138138
139139 # deprecated
140- f_loss_batch : Callable = None ,
141- fun_inputs : Callable = None ,
140+ f_loss_batch : Optional [ Callable ] = None ,
141+ fun_inputs : Optional [ Callable ] = None ,
142142 ):
143143 super ().__init__ ()
144144
@@ -149,7 +149,7 @@ def __init__(
149149
150150 # update function
151151 if target_vars is None :
152- self .target_vars = bm .ArrayCollector ()
152+ self .target_vars : bm . ArrayCollector = bm .ArrayCollector ()
153153 else :
154154 if not isinstance (target_vars , dict ):
155155 raise TypeError (f'"target_vars" must be a dict but we got { type (target_vars )} ' )
@@ -181,14 +181,14 @@ def __init__(
181181 else :
182182 self .target_vars = all_vars
183183 if len (excluded_vars ):
184- excluded_vars = [id (v ) for v in excluded_vars ]
184+ excluded_ids = [id (v ) for v in excluded_vars ]
185185 for key , val in tuple (self .target_vars .items ()):
186- if id (val ) in excluded_vars :
186+ if id (val ) in excluded_ids :
187187 self .target_vars .pop (key )
188188
189189 # input function
190190 if callable (inputs ):
191- self ._inputs = inputs
191+ self ._inputs : Any = inputs
192192 else :
193193 if inputs is None :
194194 self ._inputs = None
@@ -258,13 +258,13 @@ def __init__(
258258 self .f_loss = f_loss
259259
260260 # essential variables
261- self ._losses = None
262- self ._fixed_points = None
263- self ._selected_ids = None
264- self ._opt_losses = None
261+ self ._losses : Any = None
262+ self ._fixed_points : Any = None
263+ self ._selected_ids : Any = None
264+ self ._opt_losses : Any = None
265265
266266 # functions
267- self ._opt_functions = dict ()
267+ self ._opt_functions : Dict [ str , Any ] = dict ()
268268
269269 @property
270270 def opt_losses (self ) -> np .ndarray :
@@ -315,7 +315,7 @@ def find_fps_with_gd_method(
315315 tolerance : Union [float , Dict [str , float ]] = 1e-5 ,
316316 num_batch : int = 100 ,
317317 num_opt : int = 10000 ,
318- optimizer : optim .Optimizer = None ,
318+ optimizer : Optional [ optim .Optimizer ] = None ,
319319 ):
320320 """Optimize fixed points with gradient descent methods.
321321
@@ -456,9 +456,9 @@ def find_fps_with_opt_solver(
456456 indices = [0 ]
457457 for v in candidates .values ():
458458 indices .append (v .shape [1 ])
459- indices = np .cumsum (indices )
459+ offsets = np .cumsum (indices )
460460 keys = tuple (candidates .keys ())
461- self ._fixed_points = {key : fixed_points [:, indices [i ]: indices [i + 1 ]]
461+ self ._fixed_points = {key : fixed_points [:, offsets [i ]: offsets [i + 1 ]]
462462 for i , key in enumerate (keys )}
463463 else :
464464 self ._fixed_points = fixed_points
@@ -538,7 +538,9 @@ def exclude_outliers(self, tolerance: float = 1e0):
538538 return
539539
540540 # Compute pairwise distances between all fixed points.
541- distances = np .asarray (utils .euclidean_distance_jax (self .fixed_points , num_fps ))
541+ # ``fixed_points`` property returns ndarray-or-dict; the outlier path
542+ # operates on the array branch, so narrow it for the distance helper.
543+ distances = np .asarray (utils .euclidean_distance_jax (cast (jnp .ndarray , self .fixed_points ), num_fps ))
542544
543545 # Find the second smallest element in each column of the pairwise distance matrix.
544546 # This corresponds to the closest neighbor for each fixed point.
@@ -597,7 +599,9 @@ def compute_jacobians(
597599 else :
598600 raise ValueError ('Only support points of 1D: (num_feature,) or 2D: (num_point, num_feature)' )
599601 if isinstance (points , dict ) and stack_dict_var :
600- points = jnp .hstack (tuple (points .values ()))
602+ # ``points`` is a constrained-TypeVar param; stacking a dict yields a
603+ # concrete jax.Array that mypy cannot reconcile with every constraint.
604+ points = jnp .hstack (tuple (points .values ())) # type: ignore[assignment, arg-type]
601605
602606 # get Jacobian matrix
603607 jacobian = self ._get_f_jocabian (stack_dict_var )(points )
@@ -761,8 +765,8 @@ def call_opt(x):
761765
762766 def _generate_ds_cell_function (
763767 self , target ,
764- t : float = None ,
765- dt : float = None ,
768+ t : Optional [ float ] = None ,
769+ dt : Optional [ float ] = None ,
766770 ):
767771 if dt is None : dt = bm .get_dt ()
768772 if t is None : t = 0.
0 commit comments