@@ -123,6 +123,57 @@ def pad_and_guard_edges(
123123 return ei , ev , edge_mask
124124
125125
126+ def pad_and_guard_angles (
127+ angle_index : Array ,
128+ angle_capacity : int | None = None ,
129+ min_angles : int = 2 ,
130+ pad_value : int = 0 ,
131+ ) -> tuple [Array , Array ]:
132+ """Append padding/guard angles as a contiguous suffix and build angle_mask.
133+
134+ Real angles (``angle_index``) stay at the front (compact layout).
135+ Dummy angles point at edge ``pad_value`` (in-range).
136+
137+ Parameters
138+ ----------
139+ angle_index
140+ (2, A_real) ``[edge_a, edge_b]`` edge endpoints of the real angles.
141+ angle_capacity
142+ Target angle-axis length ``A_max``. ``None`` (torch dynamic) appends
143+ exactly ``min_angles`` masked dummy angles so the axis has a known lower
144+ bound and shape-stable guards for export; an int (jax static) pads to
145+ ``A_max = angle_capacity`` and raises ``ValueError`` on overflow.
146+ min_angles
147+ Number of dummy angles appended when ``angle_capacity is None``.
148+ pad_value
149+ Edge index the dummy angles point at (must be in range).
150+
151+ Returns
152+ -------
153+ angle_index
154+ (2, target) padded angle endpoints.
155+ angle_mask
156+ (target,) boolean mask, ``True`` for the real-angle prefix.
157+ """
158+ xp = array_api_compat .array_namespace (angle_index )
159+ dev = array_api_compat .device (angle_index )
160+ a_real = angle_index .shape [1 ]
161+ if angle_capacity is None :
162+ target = a_real + min_angles
163+ else :
164+ if a_real > angle_capacity :
165+ raise ValueError (
166+ f"angle overflow: { a_real } real angles > angle_capacity { angle_capacity } "
167+ )
168+ target = angle_capacity
169+ n_pad = target - a_real
170+ pad_idx = xp .full ((2 , n_pad ), pad_value , dtype = angle_index .dtype , device = dev )
171+ ai = xp .concat ([angle_index , pad_idx ], axis = 1 )
172+ arange = xp .arange (target , dtype = angle_index .dtype , device = dev )
173+ angle_mask = arange < a_real
174+ return ai , angle_mask
175+
176+
126177def frame_id_from_n_node (n_node : Array , n_total : int | None = None ) -> Array :
127178 """Node->frame map for a flat node axis: ``repeat(arange(nf), n_node)``.
128179
0 commit comments