@@ -90,6 +90,9 @@ def random_slice(self, length: int, padded_sampling: str = "none"):
9090 where the start of the training sequence is not always the first timestep of the trajectory.
9191 "right" --> sample while effectively padding the right side of the sequence for cases
9292 where the end of the trajectory may be undersampled.
93+ "center" --> uniform random window center, clamped to valid range.
94+ Always returns a full-length (never padded) window. Fixes endpoint
95+ undersampling of "none" when the trajectory is longer than `length`.
9396 """
9497 if len (self ) <= length :
9598 start = 0
@@ -101,6 +104,16 @@ def random_slice(self, length: int, padded_sampling: str = "none"):
101104 start = self ._safe_randrange (- length + 1 , len (self ) - length + 1 )
102105 elif padded_sampling == "right" :
103106 start = self ._safe_randrange (0 , len (self ) - 1 )
107+ elif padded_sampling == "center" :
108+ # Uniform center over [0, T), window clamped to fit inside [0, T].
109+ # Always length `length`, never padded. Compared to "none", which
110+ # severely undersamples the first/last (length - 1) timesteps,
111+ # this mode gives them ~length/T marginal coverage instead of
112+ # ~1/(T-length+1). Trade-off: interior timesteps still get more
113+ # coverage than endpoints when T < 2*length - 1, but the
114+ # imbalance is dramatically smaller than "none".
115+ center = self ._safe_randrange (0 , len (self ))
116+ start = min (max (center - length // 2 , 0 ), len (self ) - length )
104117 else :
105118 raise ValueError (
106119 f"Unrecognized `padded_sampling` mode: `{ padded_sampling } `"
0 commit comments