1use crate::ElementConversion;
4use core::num::NonZeroUsize;
5
6pub(crate) fn check_nonzero(value: usize, msg: &str) -> usize {
9 NonZeroUsize::new(value).expect(msg);
10 value
11}
12
13#[derive(Debug, Clone, Hash, PartialEq, Eq)]
15pub struct ConvOptions<const N: usize> {
16 pub stride: [usize; N],
18
19 pub padding: [usize; N],
21
22 pub dilation: [usize; N],
24
25 pub groups: usize,
27}
28
29impl<const N: usize> ConvOptions<N> {
30 pub fn new(
32 stride: [usize; N],
33 padding: [usize; N],
34 dilation: [usize; N],
35 groups: usize,
36 ) -> Self {
37 Self {
38 stride: stride.map(|s| check_nonzero(s, "stride must be non-zero")),
39 padding,
40 dilation: dilation.map(|d| check_nonzero(d, "dilation must be non-zero")),
41 groups: check_nonzero(groups, "groups must be non-zero"),
42 }
43 }
44}
45
46#[derive(Debug, Clone)]
55pub struct PaddedConvOptions<const N: usize> {
56 pub options: ConvOptions<N>,
58 pub padding_end: Option<[usize; N]>,
62}
63
64impl<const N: usize> PaddedConvOptions<N> {
65 pub fn asymmetric(
70 stride: [usize; N],
71 padding_start: [usize; N],
72 padding_end: [usize; N],
73 dilation: [usize; N],
74 groups: usize,
75 ) -> Self {
76 let options = ConvOptions::new(stride, padding_start, dilation, groups);
77 if padding_start == padding_end {
78 Self {
79 options,
80 padding_end: None,
81 }
82 } else {
83 Self {
84 options,
85 padding_end: Some(padding_end),
86 }
87 }
88 }
89
90 pub fn is_asymmetric(&self) -> bool {
92 self.padding_end.is_some()
93 }
94}
95
96impl<const N: usize> From<ConvOptions<N>> for PaddedConvOptions<N> {
97 fn from(options: ConvOptions<N>) -> Self {
98 Self {
99 options,
100 padding_end: None,
101 }
102 }
103}
104
105#[derive(Debug, Clone, Hash, PartialEq, Eq)]
107pub struct DeformConvOptions<const N: usize> {
108 pub stride: [usize; N],
110
111 pub padding: [usize; N],
113
114 pub dilation: [usize; N],
116
117 pub weight_groups: usize,
119
120 pub offset_groups: usize,
122}
123
124impl<const N: usize> DeformConvOptions<N> {
125 pub fn new(
127 stride: [usize; N],
128 padding: [usize; N],
129 dilation: [usize; N],
130 weight_groups: usize,
131 offset_groups: usize,
132 ) -> Self {
133 Self {
134 stride: stride.map(|s| check_nonzero(s, "stride must be non-zero")),
135 padding,
136 dilation: dilation.map(|d| check_nonzero(d, "dilation must be non-zero")),
137 weight_groups: check_nonzero(weight_groups, "weight groups must be non-zero"),
138 offset_groups: check_nonzero(offset_groups, "offset groups must be non-zero"),
139 }
140 }
141}
142
143#[derive(Debug, Clone, Hash, PartialEq, Eq)]
145pub struct ConvTransposeOptions<const N: usize> {
146 pub stride: [usize; N],
148
149 pub padding: [usize; N],
151
152 pub padding_out: [usize; N],
154
155 pub dilation: [usize; N],
157
158 pub groups: usize,
160}
161
162impl<const N: usize> ConvTransposeOptions<N> {
163 pub fn new(
165 stride: [usize; N],
166 padding: [usize; N],
167 padding_out: [usize; N],
168 dilation: [usize; N],
169 groups: usize,
170 ) -> Self {
171 Self {
172 stride: stride.map(|s| check_nonzero(s, "stride must be non-zero")),
173 padding,
174 padding_out,
175 dilation: dilation.map(|d| check_nonzero(d, "dilation must be non-zero")),
176 groups: check_nonzero(groups, "groups must be non-zero"),
177 }
178 }
179}
180
181#[derive(Debug, Clone)]
183pub struct UnfoldOptions {
184 pub stride: [usize; 2],
187
188 pub padding: [usize; 2],
190
191 pub dilation: [usize; 2],
193}
194
195impl UnfoldOptions {
196 pub fn new(stride: [usize; 2], padding: [usize; 2], dilation: [usize; 2]) -> Self {
198 Self {
199 stride: stride.map(|s| check_nonzero(s, "stride must be non-zero")),
200 padding,
201 dilation: dilation.map(|d| check_nonzero(d, "dilation must be non-zero")),
202 }
203 }
204}
205
206#[derive(new, Debug, Clone, serde::Deserialize, serde::Serialize)]
208pub enum InterpolateMode {
209 Nearest,
213
214 NearestExact,
217
218 Bilinear,
221
222 Bicubic,
225
226 Lanczos3,
229}
230
231#[derive(Debug, Clone)]
233pub struct InterpolateOptions {
234 pub mode: InterpolateMode,
236 pub align_corners: bool,
239}
240
241impl InterpolateOptions {
242 pub fn new(mode: InterpolateMode) -> Self {
245 Self {
246 mode,
247 align_corners: true,
248 }
249 }
250
251 pub fn with_align_corners(mut self, align_corners: bool) -> Self {
253 self.align_corners = align_corners;
254 self
255 }
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Deserialize, serde::Serialize)]
262pub enum GridSamplePaddingMode {
263 #[default]
265 Zeros,
266 Border,
268 Reflection,
270}
271
272#[derive(Debug, Clone)]
274pub struct GridSampleOptions {
275 pub mode: InterpolateMode,
277 pub padding_mode: GridSamplePaddingMode,
279 pub align_corners: bool,
283}
284
285impl Default for GridSampleOptions {
286 fn default() -> Self {
287 Self {
288 mode: InterpolateMode::Bilinear,
289 padding_mode: GridSamplePaddingMode::Zeros,
290 align_corners: false,
291 }
292 }
293}
294
295impl From<InterpolateMode> for GridSampleOptions {
296 fn from(value: InterpolateMode) -> Self {
297 GridSampleOptions::new(value)
298 }
299}
300
301impl GridSampleOptions {
302 pub fn new(mode: InterpolateMode) -> Self {
306 Self {
307 mode,
308 ..Default::default()
309 }
310 }
311
312 pub fn with_padding_mode(mut self, padding_mode: GridSamplePaddingMode) -> Self {
314 self.padding_mode = padding_mode;
315 self
316 }
317
318 pub fn with_align_corners(mut self, align_corners: bool) -> Self {
320 self.align_corners = align_corners;
321 self
322 }
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, serde::Deserialize, serde::Serialize)]
336pub enum PadMode {
337 Constant(f32),
343
344 Reflect,
352
353 Edge,
359}
360
361impl Default for PadMode {
362 fn default() -> Self {
363 PadMode::Constant(0.0)
364 }
365}
366
367impl<E: ElementConversion> From<E> for PadMode {
368 fn from(value: E) -> Self {
369 PadMode::Constant(value.elem())
370 }
371}
372
373#[derive(Debug, Clone, Copy, Default, PartialEq, serde::Deserialize, serde::Serialize)]
375pub struct AttentionModuleOptions {
376 pub scale: Option<f64>,
378
379 pub softcap: Option<f64>,
382
383 pub is_causal: bool,
388}
389
390#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
392pub enum IndexingUpdateOp {
393 Assign,
395 Add,
397 Mul,
399 Min,
401 Max,
403}
404
405#[cfg(test)]
406mod tests {
407 use super::*;
408
409 #[test]
410 #[should_panic = "stride must be non-zero"]
411 fn conv_options_stride_zero() {
412 let _opt = ConvOptions::new([0, 1], [0, 0], [1, 1], 1);
413 }
414
415 #[test]
416 #[should_panic = "dilation must be non-zero"]
417 fn conv_options_dilation_zero() {
418 let _opt = ConvOptions::new([1, 1], [0, 0], [0, 0], 1);
419 }
420
421 #[test]
422 #[should_panic = "groups must be non-zero"]
423 fn conv_options_groups_zero() {
424 let _opt = ConvOptions::new([1, 1], [0, 0], [1, 1], 0);
425 }
426
427 #[test]
428 #[should_panic = "stride must be non-zero"]
429 fn conv_transpose_options_stride_zero() {
430 let _opt = ConvTransposeOptions::new([0, 1], [0, 0], [0, 0], [1, 1], 1);
431 }
432
433 #[test]
434 #[should_panic = "dilation must be non-zero"]
435 fn conv_transpose_options_dilation_zero() {
436 let _opt = ConvTransposeOptions::new([1, 1], [0, 0], [0, 0], [0, 0], 1);
437 }
438
439 #[test]
440 #[should_panic = "groups must be non-zero"]
441 fn conv_transpose_options_groups_zero() {
442 let _opt = ConvTransposeOptions::new([1, 1], [0, 0], [0, 0], [1, 1], 0);
443 }
444
445 #[test]
446 #[should_panic = "stride must be non-zero"]
447 fn deform_conv_options_stride_zero() {
448 let _opt = DeformConvOptions::new([0, 1], [0, 0], [1, 1], 1, 1);
449 }
450
451 #[test]
452 #[should_panic = "dilation must be non-zero"]
453 fn deform_conv_options_dilation_zero() {
454 let _opt = DeformConvOptions::new([1, 1], [0, 0], [0, 0], 1, 1);
455 }
456
457 #[test]
458 #[should_panic = "weight groups must be non-zero"]
459 fn deform_conv_options_weights_groups_zero() {
460 let _opt = DeformConvOptions::new([1, 1], [0, 0], [1, 1], 0, 1);
461 }
462
463 #[test]
464 #[should_panic = "offset groups must be non-zero"]
465 fn deform_conv_options_offset_groups_zero() {
466 let _opt = DeformConvOptions::new([1, 1], [0, 0], [1, 1], 1, 0);
467 }
468
469 #[test]
470 #[should_panic = "stride must be non-zero"]
471 fn unfold_options_stride_zero() {
472 let _opt = UnfoldOptions::new([0, 1], [0, 0], [1, 1]);
473 }
474
475 #[test]
476 #[should_panic = "dilation must be non-zero"]
477 fn unfold_options_dilation_zero() {
478 let _opt = UnfoldOptions::new([1, 1], [0, 0], [0, 0]);
479 }
480}