Skip to main content

flodl_sys/
lib.rs

1//! Raw FFI bindings to the libtorch C++ shim.
2//!
3//! Every function that can fail returns a `*mut c_char` error string (caller
4//! must free it with [`flodl_free_string`]). A null pointer means success.
5//!
6//! `FlodlTensor` is an opaque `*mut c_void` handle to a heap-allocated
7//! `torch::Tensor`. Caller owns it and must free with [`flodl_free_tensor`].
8
9use std::ffi::{c_char, c_void};
10
11/// Parses `shim.h` + this file and asserts the two `extern "C"` surfaces
12/// match (ABI). Guards the hand-written bindings against silent drift.
13#[cfg(test)]
14mod ffi_parity;
15
16/// Opaque handle to a `torch::Tensor` on the C++ side.
17pub type FlodlTensor = *mut c_void;
18
19// --- DType constants (must match shim.h) ---
20pub const FLODL_FLOAT16: i32 = 5;
21pub const FLODL_BFLOAT16: i32 = 15;
22pub const FLODL_FLOAT32: i32 = 6;
23pub const FLODL_FLOAT64: i32 = 7;
24pub const FLODL_INT32: i32 = 3;
25pub const FLODL_INT64: i32 = 4;
26
27// --- Device constants (must match shim.h) ---
28pub const FLODL_CPU: i32 = 0;
29pub const FLODL_CUDA: i32 = 1;
30
31unsafe extern "C" {
32    // --- Tensor creation ---
33
34    pub fn flodl_zeros(
35        shape: *mut i64, ndim: i32, dtype: i32,
36        device_type: i32, device_index: i32,
37        result: *mut FlodlTensor,
38    ) -> *mut c_char;
39
40    pub fn flodl_ones(
41        shape: *mut i64, ndim: i32, dtype: i32,
42        device_type: i32, device_index: i32,
43        result: *mut FlodlTensor,
44    ) -> *mut c_char;
45
46    pub fn flodl_rand(
47        shape: *mut i64, ndim: i32, dtype: i32,
48        device_type: i32, device_index: i32,
49        result: *mut FlodlTensor,
50    ) -> *mut c_char;
51
52    pub fn flodl_randn(
53        shape: *mut i64, ndim: i32, dtype: i32,
54        device_type: i32, device_index: i32,
55        result: *mut FlodlTensor,
56    ) -> *mut c_char;
57
58    pub fn flodl_from_blob(
59        data: *mut c_void, shape: *mut i64, ndim: i32,
60        dtype: i32, device_type: i32, device_index: i32,
61        result: *mut FlodlTensor,
62    ) -> *mut c_char;
63
64    pub fn flodl_linspace(
65        start: f64, end: f64, steps: i64,
66        dtype: i32, device_type: i32, device_index: i32,
67        result: *mut FlodlTensor,
68    ) -> *mut c_char;
69
70    pub fn flodl_arange(
71        start: f64, end: f64, step: f64,
72        dtype: i32, device_type: i32, device_index: i32,
73        result: *mut FlodlTensor,
74    ) -> *mut c_char;
75
76    pub fn flodl_expand(
77        t: FlodlTensor, new_shape: *mut i64, ndim: i32,
78        result: *mut FlodlTensor,
79    ) -> *mut c_char;
80
81    // --- Tensor lifecycle ---
82
83    pub fn flodl_free_tensor(t: FlodlTensor);
84    pub fn flodl_shallow_clone(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
85    pub fn flodl_deep_clone(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
86
87    // --- Tensor metadata ---
88
89    pub fn flodl_ndim(t: FlodlTensor) -> i32;
90    pub fn flodl_shape(t: FlodlTensor, dim: i32) -> i64;
91    pub fn flodl_dtype(t: FlodlTensor) -> i32;
92    pub fn flodl_device_type(t: FlodlTensor) -> i32;
93    pub fn flodl_device_index(t: FlodlTensor) -> i32;
94    pub fn flodl_numel(t: FlodlTensor) -> i64;
95    pub fn flodl_storage_nbytes(t: FlodlTensor) -> i64;
96
97    // --- Data access ---
98
99    pub fn flodl_copy_data(
100        t: FlodlTensor, buffer: *mut c_void, buffer_bytes: i64,
101    ) -> *mut c_char;
102
103    // --- Arithmetic ---
104
105    pub fn flodl_add(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
106    pub fn flodl_sub(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
107    pub fn flodl_mul(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
108    pub fn flodl_div(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
109    pub fn flodl_matmul(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
110
111    pub fn flodl_add_scalar(
112        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
113    ) -> *mut c_char;
114
115    pub fn flodl_mul_scalar(
116        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
117    ) -> *mut c_char;
118
119    pub fn flodl_div_scalar(
120        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
121    ) -> *mut c_char;
122
123    pub fn flodl_neg(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
124
125    // --- Activations ---
126
127    pub fn flodl_relu(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
128    pub fn flodl_sigmoid(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
129    pub fn flodl_tanh_op(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
130    pub fn flodl_softmax(t: FlodlTensor, dim: i32, result: *mut FlodlTensor) -> *mut c_char;
131    pub fn flodl_log_softmax(t: FlodlTensor, dim: i32, result: *mut FlodlTensor) -> *mut c_char;
132    pub fn flodl_gelu(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
133    pub fn flodl_gelu_tanh(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
134    pub fn flodl_silu(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
135    pub fn flodl_leaky_relu(
136        t: FlodlTensor, negative_slope: f64, result: *mut FlodlTensor,
137    ) -> *mut c_char;
138    pub fn flodl_elu(t: FlodlTensor, alpha: f64, result: *mut FlodlTensor) -> *mut c_char;
139    pub fn flodl_softplus(
140        t: FlodlTensor, beta: f64, threshold: f64, result: *mut FlodlTensor,
141    ) -> *mut c_char;
142    pub fn flodl_mish(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
143    pub fn flodl_selu(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
144    pub fn flodl_hardswish(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
145    pub fn flodl_hardsigmoid(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
146    pub fn flodl_prelu(t: FlodlTensor, weight: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
147
148    // --- Layer normalization ---
149
150    pub fn flodl_native_layer_norm(
151        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
152        normalized_size: i64, eps: f64,
153        output: *mut FlodlTensor, mean: *mut FlodlTensor, rstd: *mut FlodlTensor,
154    ) -> *mut c_char;
155
156    // --- Group normalization ---
157
158    pub fn flodl_group_norm(
159        input: FlodlTensor, num_groups: i64,
160        weight: FlodlTensor, bias: FlodlTensor,
161        eps: f64, result: *mut FlodlTensor,
162    ) -> *mut c_char;
163
164    // --- Element-wise math ---
165
166    pub fn flodl_exp(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
167    pub fn flodl_log(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
168    pub fn flodl_sqrt(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
169    pub fn flodl_abs(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
170    pub fn flodl_triu(t: FlodlTensor, diagonal: i64, result: *mut FlodlTensor) -> *mut c_char;
171    pub fn flodl_tril(t: FlodlTensor, diagonal: i64, result: *mut FlodlTensor) -> *mut c_char;
172
173    pub fn flodl_pow_scalar(
174        t: FlodlTensor, exponent: f64, result: *mut FlodlTensor,
175    ) -> *mut c_char;
176
177    pub fn flodl_clamp(
178        t: FlodlTensor, min_val: f64, max_val: f64, result: *mut FlodlTensor,
179    ) -> *mut c_char;
180
181    pub fn flodl_clamp_min(
182        t: FlodlTensor, min_val: f64, result: *mut FlodlTensor,
183    ) -> *mut c_char;
184
185    pub fn flodl_clamp_max(
186        t: FlodlTensor, max_val: f64, result: *mut FlodlTensor,
187    ) -> *mut c_char;
188
189    pub fn flodl_log1p(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
190    pub fn flodl_expm1(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
191    pub fn flodl_log2(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
192    pub fn flodl_log10(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
193
194    // --- Reductions ---
195
196    pub fn flodl_sum(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
197    pub fn flodl_mean(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
198
199    pub fn flodl_sum_dim(
200        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
201    ) -> *mut c_char;
202
203    pub fn flodl_mean_dim(
204        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
205    ) -> *mut c_char;
206
207    pub fn flodl_prod(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
208
209    pub fn flodl_prod_dim(
210        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
211    ) -> *mut c_char;
212
213    pub fn flodl_cumsum(
214        t: FlodlTensor, dim: i32, result: *mut FlodlTensor,
215    ) -> *mut c_char;
216
217    pub fn flodl_logsumexp(
218        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
219    ) -> *mut c_char;
220
221    pub fn flodl_min(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
222    pub fn flodl_max(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
223    pub fn flodl_norm(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
224
225    pub fn flodl_min_dim(
226        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
227    ) -> *mut c_char;
228
229    pub fn flodl_max_dim(
230        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
231    ) -> *mut c_char;
232
233    pub fn flodl_argmax(
234        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
235    ) -> *mut c_char;
236
237    // --- Comparison (return float masks: 0.0 or 1.0) ---
238
239    pub fn flodl_gt_scalar(
240        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
241    ) -> *mut c_char;
242
243    pub fn flodl_ge_scalar(
244        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
245    ) -> *mut c_char;
246
247    pub fn flodl_le_scalar(
248        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
249    ) -> *mut c_char;
250
251    pub fn flodl_lt_scalar(
252        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
253    ) -> *mut c_char;
254
255    pub fn flodl_eq_scalar(
256        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
257    ) -> *mut c_char;
258
259    pub fn flodl_ne_scalar(
260        t: FlodlTensor, scalar: f64, result: *mut FlodlTensor,
261    ) -> *mut c_char;
262
263    // --- Boolean / detection (return float masks) ---
264
265    pub fn flodl_isnan(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
266    pub fn flodl_isinf(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
267    pub fn flodl_logical_and(
268        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
269    ) -> *mut c_char;
270    pub fn flodl_logical_or(
271        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
272    ) -> *mut c_char;
273    pub fn flodl_logical_not(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
274    pub fn flodl_any(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
275    pub fn flodl_all(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
276
277    // --- Shape operations ---
278
279    pub fn flodl_reshape(
280        t: FlodlTensor, shape: *mut i64, ndim: i32, result: *mut FlodlTensor,
281    ) -> *mut c_char;
282
283    pub fn flodl_transpose(
284        t: FlodlTensor, dim0: i32, dim1: i32, result: *mut FlodlTensor,
285    ) -> *mut c_char;
286
287    pub fn flodl_permute(
288        t: FlodlTensor, dims: *mut i64, ndim: i32, result: *mut FlodlTensor,
289    ) -> *mut c_char;
290
291    pub fn flodl_select(
292        t: FlodlTensor, dim: i32, index: i64, result: *mut FlodlTensor,
293    ) -> *mut c_char;
294
295    pub fn flodl_narrow(
296        t: FlodlTensor, dim: i32, start: i64, length: i64,
297        result: *mut FlodlTensor,
298    ) -> *mut c_char;
299
300    pub fn flodl_squeeze(
301        t: FlodlTensor, dim: i32, result: *mut FlodlTensor,
302    ) -> *mut c_char;
303
304    pub fn flodl_unsqueeze(
305        t: FlodlTensor, dim: i32, result: *mut FlodlTensor,
306    ) -> *mut c_char;
307
308    pub fn flodl_flatten(
309        t: FlodlTensor, start_dim: i32, end_dim: i32, result: *mut FlodlTensor,
310    ) -> *mut c_char;
311
312    // --- Scatter ---
313
314    pub fn flodl_select_scatter(
315        input: FlodlTensor, src: FlodlTensor, dim: i32, index: i64,
316        result: *mut FlodlTensor,
317    ) -> *mut c_char;
318
319    pub fn flodl_narrow_scatter(
320        input: FlodlTensor, src: FlodlTensor, dim: i32, start: i64,
321        result: *mut FlodlTensor,
322    ) -> *mut c_char;
323
324    // --- Indexing ---
325
326    pub fn flodl_index_select(
327        t: FlodlTensor, dim: i32, index: FlodlTensor,
328        result: *mut FlodlTensor,
329    ) -> *mut c_char;
330
331    pub fn flodl_index_add(
332        t: FlodlTensor, dim: i32, index: FlodlTensor, src: FlodlTensor,
333        result: *mut FlodlTensor,
334    ) -> *mut c_char;
335
336    // --- Concatenation ---
337
338    pub fn flodl_cat2(
339        a: FlodlTensor, b: FlodlTensor, dim: i32, result: *mut FlodlTensor,
340    ) -> *mut c_char;
341
342    pub fn flodl_cat(
343        tensors: *mut FlodlTensor, count: i32, dim: i32, result: *mut FlodlTensor,
344    ) -> *mut c_char;
345
346    pub fn flodl_stack(
347        tensors: *mut FlodlTensor, count: i32, dim: i32, result: *mut FlodlTensor,
348    ) -> *mut c_char;
349
350    // --- Masking ---
351
352    pub fn flodl_masked_fill(
353        t: FlodlTensor, mask: FlodlTensor, value: f64,
354        result: *mut FlodlTensor,
355    ) -> *mut c_char;
356
357    // --- Conditional ---
358
359    pub fn flodl_where(
360        condition: FlodlTensor, x: FlodlTensor, y: FlodlTensor,
361        result: *mut FlodlTensor,
362    ) -> *mut c_char;
363
364    // --- Like constructors ---
365
366    pub fn flodl_zeros_like(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
367    pub fn flodl_ones_like(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
368    pub fn flodl_full_like(
369        t: FlodlTensor, value: f64, result: *mut FlodlTensor,
370    ) -> *mut c_char;
371    pub fn flodl_rand_like(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
372    pub fn flodl_randn_like(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
373
374    // --- Tensor creation (tier 2) ---
375
376    pub fn flodl_randint(
377        low: i64, high: i64, shape: *mut i64, ndim: i32,
378        dtype: i32, device_type: i32, device_index: i32,
379        result: *mut FlodlTensor,
380    ) -> *mut c_char;
381
382    pub fn flodl_empty(
383        shape: *mut i64, ndim: i32, dtype: i32,
384        device_type: i32, device_index: i32,
385        result: *mut FlodlTensor,
386    ) -> *mut c_char;
387
388    pub fn flodl_one_hot(
389        t: FlodlTensor, num_classes: i64,
390        result: *mut FlodlTensor,
391    ) -> *mut c_char;
392
393    pub fn flodl_bernoulli(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
394
395    // --- Convolution ---
396
397    pub fn flodl_conv2d(
398        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
399        stride: *mut i64, padding: *mut i64, dilation: *mut i64,
400        groups: i64, result: *mut FlodlTensor,
401    ) -> *mut c_char;
402
403    // --- 1D convolution ---
404
405    pub fn flodl_conv1d(
406        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
407        stride: i64, padding: i64, dilation: i64,
408        groups: i64, result: *mut FlodlTensor,
409    ) -> *mut c_char;
410
411    // --- Transposed convolution ---
412
413    pub fn flodl_conv_transpose2d(
414        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
415        stride: *mut i64, padding: *mut i64,
416        output_padding: *mut i64, dilation: *mut i64,
417        groups: i64, result: *mut FlodlTensor,
418    ) -> *mut c_char;
419
420    // --- Transposed 1D convolution ---
421
422    pub fn flodl_conv_transpose1d(
423        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
424        stride: i64, padding: i64,
425        output_padding: i64, dilation: i64,
426        groups: i64, result: *mut FlodlTensor,
427    ) -> *mut c_char;
428
429    // --- Pooling ---
430
431    pub fn flodl_max_pool2d(
432        input: FlodlTensor, kernel_size: *mut i64,
433        stride: *mut i64, padding: *mut i64, dilation: *mut i64,
434        ceil_mode: i32, result: *mut FlodlTensor,
435    ) -> *mut c_char;
436
437    pub fn flodl_avg_pool2d(
438        input: FlodlTensor, kernel_size: *mut i64,
439        stride: *mut i64, padding: *mut i64,
440        ceil_mode: i32, count_include_pad: i32,
441        result: *mut FlodlTensor,
442    ) -> *mut c_char;
443
444    pub fn flodl_adaptive_avg_pool2d(
445        input: FlodlTensor, output_size: *mut i64,
446        result: *mut FlodlTensor,
447    ) -> *mut c_char;
448
449    pub fn flodl_adaptive_max_pool2d(
450        input: FlodlTensor, output_size: *mut i64,
451        result: *mut FlodlTensor,
452    ) -> *mut c_char;
453
454    // --- Unfold / Fold (im2col / col2im) ---
455
456    pub fn flodl_im2col(
457        input: FlodlTensor, kernel_size: *mut i64, dilation: *mut i64,
458        padding: *mut i64, stride: *mut i64, result: *mut FlodlTensor,
459    ) -> *mut c_char;
460
461    pub fn flodl_col2im(
462        input: FlodlTensor, output_size: *mut i64,
463        kernel_size: *mut i64, dilation: *mut i64,
464        padding: *mut i64, stride: *mut i64, result: *mut FlodlTensor,
465    ) -> *mut c_char;
466
467    // --- 3D convolution ---
468
469    pub fn flodl_conv3d(
470        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
471        stride: *mut i64, padding: *mut i64, dilation: *mut i64,
472        groups: i64, result: *mut FlodlTensor,
473    ) -> *mut c_char;
474
475    pub fn flodl_conv_transpose3d(
476        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
477        stride: *mut i64, padding: *mut i64, output_padding: *mut i64,
478        dilation: *mut i64, groups: i64, result: *mut FlodlTensor,
479    ) -> *mut c_char;
480
481    // --- 1D pooling ---
482
483    pub fn flodl_max_pool1d(
484        input: FlodlTensor, kernel_size: i64,
485        stride: i64, padding: i64, dilation: i64,
486        ceil_mode: i32, result: *mut FlodlTensor,
487    ) -> *mut c_char;
488
489    pub fn flodl_avg_pool1d(
490        input: FlodlTensor, kernel_size: i64,
491        stride: i64, padding: i64,
492        ceil_mode: i32, count_include_pad: i32,
493        result: *mut FlodlTensor,
494    ) -> *mut c_char;
495
496    // --- Instance normalization ---
497
498    pub fn flodl_instance_norm(
499        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
500        running_mean: FlodlTensor, running_var: FlodlTensor,
501        use_input_stats: i32, momentum: f64, eps: f64,
502        result: *mut FlodlTensor,
503    ) -> *mut c_char;
504
505    // --- PixelShuffle ---
506
507    pub fn flodl_pixel_shuffle(
508        input: FlodlTensor, upscale_factor: i64, result: *mut FlodlTensor,
509    ) -> *mut c_char;
510
511    pub fn flodl_pixel_unshuffle(
512        input: FlodlTensor, downscale_factor: i64, result: *mut FlodlTensor,
513    ) -> *mut c_char;
514
515    // --- Bilinear ---
516
517    pub fn flodl_bilinear(
518        input1: FlodlTensor, input2: FlodlTensor,
519        weight: FlodlTensor, bias: FlodlTensor,
520        result: *mut FlodlTensor,
521    ) -> *mut c_char;
522
523    // --- Grid sampling ---
524
525    pub fn flodl_grid_sample(
526        input: FlodlTensor, grid: FlodlTensor,
527        mode: i32, padding_mode: i32, align_corners: i32,
528        result: *mut FlodlTensor,
529    ) -> *mut c_char;
530
531    // --- Scaled dot-product attention ---
532
533    pub fn flodl_scaled_dot_product_attention(
534        query: FlodlTensor, key: FlodlTensor, value: FlodlTensor,
535        attn_mask: FlodlTensor,
536        dropout_p: f64, is_causal: i32, scale: f64,
537        result: *mut FlodlTensor,
538    ) -> *mut c_char;
539
540    // --- Device ---
541
542    pub fn flodl_to_device(
543        t: FlodlTensor, device_type: i32, device_index: i32,
544        result: *mut FlodlTensor,
545    ) -> *mut c_char;
546
547    pub fn flodl_to_device_async(
548        t: FlodlTensor, device_type: i32, device_index: i32,
549        result: *mut FlodlTensor,
550    ) -> *mut c_char;
551
552    pub fn flodl_cuda_is_available() -> i32;
553    pub fn flodl_cuda_device_count() -> i32;
554    pub fn flodl_force_cuda_link() -> i32;
555    pub fn flodl_set_current_device(device_index: i32);
556    pub fn flodl_get_current_device() -> i32;
557    pub fn flodl_cuda_synchronize(device_index: i32);
558
559    // --- CUDA memory/utilization (monitor support) ---
560
561    pub fn flodl_cuda_mem_info(
562        device_index: i32, used_bytes: *mut u64, total_bytes: *mut u64,
563    ) -> *mut c_char;
564
565    pub fn flodl_cuda_alloc_bytes(
566        device_index: i32, allocated_bytes: *mut u64,
567    ) -> *mut c_char;
568
569    pub fn flodl_cuda_active_bytes(
570        device_index: i32, active_bytes: *mut u64,
571    ) -> *mut c_char;
572
573    pub fn flodl_cuda_peak_active_bytes(
574        device_index: i32, peak_bytes: *mut u64,
575    ) -> *mut c_char;
576
577    pub fn flodl_cuda_peak_reserved_bytes(
578        device_index: i32, peak_bytes: *mut u64,
579    ) -> *mut c_char;
580
581    pub fn flodl_cuda_reset_peak_stats(device_index: i32);
582
583    pub fn flodl_cuda_empty_cache();
584
585    pub fn flodl_cuda_utilization(device_index: i32) -> i32;
586
587    pub fn flodl_cuda_nvml_mem_info(
588        device_index: i32, used_bytes: *mut u64, total_bytes: *mut u64,
589    ) -> i32;
590
591    pub fn flodl_cuda_has_primary_context(device_index: i32) -> i32;
592
593    pub fn flodl_cuda_device_name(
594        device_index: i32, buf: *mut c_char, buf_len: i32,
595    ) -> *mut c_char;
596
597    pub fn flodl_cuda_compute_capability(
598        device_index: i32, major: *mut i32, minor: *mut i32,
599    ) -> *mut c_char;
600
601    // --- Dtype casting ---
602
603    pub fn flodl_to_dtype(
604        t: FlodlTensor, dtype: i32, result: *mut FlodlTensor,
605    ) -> *mut c_char;
606
607    pub fn flodl_all_finite(t: FlodlTensor, result: *mut i32) -> *mut c_char;
608
609    // --- Comparison (tensor-tensor, return float masks: 0.0 or 1.0) ---
610
611    pub fn flodl_gt_tensor(
612        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
613    ) -> *mut c_char;
614
615    pub fn flodl_lt_tensor(
616        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
617    ) -> *mut c_char;
618
619    pub fn flodl_ge_tensor(
620        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
621    ) -> *mut c_char;
622
623    pub fn flodl_le_tensor(
624        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
625    ) -> *mut c_char;
626
627    pub fn flodl_eq_tensor(
628        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
629    ) -> *mut c_char;
630
631    pub fn flodl_ne_tensor(
632        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
633    ) -> *mut c_char;
634
635    // --- Element-wise binary (differentiable) ---
636
637    pub fn flodl_atan2(
638        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
639    ) -> *mut c_char;
640
641    pub fn flodl_maximum(
642        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
643    ) -> *mut c_char;
644
645    pub fn flodl_minimum(
646        a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor,
647    ) -> *mut c_char;
648
649    // --- Additional reductions ---
650
651    pub fn flodl_argmin(
652        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
653    ) -> *mut c_char;
654
655    pub fn flodl_var(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
656    pub fn flodl_std_op(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
657
658    pub fn flodl_var_dim(
659        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
660    ) -> *mut c_char;
661
662    pub fn flodl_std_dim(
663        t: FlodlTensor, dim: i32, keepdim: i32, result: *mut FlodlTensor,
664    ) -> *mut c_char;
665
666    pub fn flodl_cumprod(t: FlodlTensor, dim: i32, result: *mut FlodlTensor) -> *mut c_char;
667    pub fn flodl_norm_p_dim(
668        t: FlodlTensor, p: f64, dim: i32, keepdim: i32, result: *mut FlodlTensor,
669    ) -> *mut c_char;
670    pub fn flodl_sum_dims(
671        t: FlodlTensor, dims: *mut i64, ndims: i32, keepdim: i32,
672        result: *mut FlodlTensor,
673    ) -> *mut c_char;
674    pub fn flodl_median(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
675    pub fn flodl_median_dim(
676        t: FlodlTensor, dim: i32, keepdim: i32,
677        values: *mut FlodlTensor, indices: *mut FlodlTensor,
678    ) -> *mut c_char;
679    pub fn flodl_count_nonzero(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
680    pub fn flodl_count_nonzero_dim(
681        t: FlodlTensor, dim: i32, result: *mut FlodlTensor,
682    ) -> *mut c_char;
683
684    // --- Query ops ---
685
686    pub fn flodl_nonzero(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
687    pub fn flodl_unique(
688        t: FlodlTensor, sorted: i32, return_inverse: i32,
689        output: *mut FlodlTensor, inverse_indices: *mut FlodlTensor,
690    ) -> *mut c_char;
691    pub fn flodl_unique_consecutive(
692        t: FlodlTensor, return_inverse: i32,
693        output: *mut FlodlTensor, inverse_indices: *mut FlodlTensor,
694    ) -> *mut c_char;
695    pub fn flodl_searchsorted(
696        sorted_seq: FlodlTensor, values: FlodlTensor,
697        result: *mut FlodlTensor,
698    ) -> *mut c_char;
699
700    // --- Shape ops (advanced) ---
701
702    pub fn flodl_diagonal(
703        t: FlodlTensor, offset: i64, dim1: i32, dim2: i32,
704        result: *mut FlodlTensor,
705    ) -> *mut c_char;
706    pub fn flodl_movedim(
707        t: FlodlTensor, src: i64, dst: i64, result: *mut FlodlTensor,
708    ) -> *mut c_char;
709    pub fn flodl_tile(
710        t: FlodlTensor, reps: *mut i64, ndim: i32, result: *mut FlodlTensor,
711    ) -> *mut c_char;
712
713    // --- Element-wise math (trig, rounding, sign) ---
714
715    pub fn flodl_sin(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
716    pub fn flodl_cos(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
717    pub fn flodl_tan(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
718    pub fn flodl_asin(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
719    pub fn flodl_acos(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
720    pub fn flodl_atan(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
721    pub fn flodl_sign(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
722    pub fn flodl_floor(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
723    pub fn flodl_ceil(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
724    pub fn flodl_round(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
725    pub fn flodl_reciprocal(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
726    pub fn flodl_erf(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
727    pub fn flodl_erfc(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
728    pub fn flodl_trunc(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
729    pub fn flodl_frac(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
730    pub fn flodl_fmod_scalar(t: FlodlTensor, scalar: f64, result: *mut FlodlTensor) -> *mut c_char;
731    pub fn flodl_fmod_tensor(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
732    pub fn flodl_remainder_scalar(t: FlodlTensor, scalar: f64, result: *mut FlodlTensor) -> *mut c_char;
733    pub fn flodl_remainder_tensor(a: FlodlTensor, b: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
734    pub fn flodl_lerp(a: FlodlTensor, b: FlodlTensor, weight: f64, result: *mut FlodlTensor) -> *mut c_char;
735    pub fn flodl_lerp_tensor(a: FlodlTensor, b: FlodlTensor, weight: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
736    pub fn flodl_isclose(a: FlodlTensor, b: FlodlTensor, rtol: f64, atol: f64, result: *mut FlodlTensor) -> *mut c_char;
737
738    // --- Fused mul-add ---
739
740    pub fn flodl_addmm(
741        bias: FlodlTensor, mat1: FlodlTensor, mat2: FlodlTensor,
742        beta: f64, alpha: f64, result: *mut FlodlTensor,
743    ) -> *mut c_char;
744    pub fn flodl_addcmul(
745        self_: FlodlTensor, t1: FlodlTensor, t2: FlodlTensor,
746        value: f64, result: *mut FlodlTensor,
747    ) -> *mut c_char;
748    pub fn flodl_addcdiv(
749        self_: FlodlTensor, t1: FlodlTensor, t2: FlodlTensor,
750        value: f64, result: *mut FlodlTensor,
751    ) -> *mut c_char;
752
753    // --- Advanced indexing ---
754
755    pub fn flodl_gather(
756        t: FlodlTensor, dim: i32, index: FlodlTensor,
757        result: *mut FlodlTensor,
758    ) -> *mut c_char;
759
760    pub fn flodl_scatter_add(
761        t: FlodlTensor, dim: i32, index: FlodlTensor, src: FlodlTensor,
762        result: *mut FlodlTensor,
763    ) -> *mut c_char;
764
765    // --- Sorting ---
766
767    pub fn flodl_topk(
768        t: FlodlTensor, k: i64, dim: i32, largest: i32, sorted: i32,
769        values: *mut FlodlTensor, indices: *mut FlodlTensor,
770    ) -> *mut c_char;
771
772    pub fn flodl_sort(
773        t: FlodlTensor, dim: i32, descending: i32,
774        values: *mut FlodlTensor, indices: *mut FlodlTensor,
775    ) -> *mut c_char;
776
777    // --- Tensor creation (additional) ---
778
779    pub fn flodl_eye(
780        n: i64, dtype: i32, device_type: i32, device_index: i32,
781        result: *mut FlodlTensor,
782    ) -> *mut c_char;
783
784    pub fn flodl_full(
785        shape: *mut i64, ndim: i32, value: f64, dtype: i32,
786        device_type: i32, device_index: i32,
787        result: *mut FlodlTensor,
788    ) -> *mut c_char;
789
790    pub fn flodl_randperm(
791        n: i64, dtype: i32, device_type: i32, device_index: i32,
792        result: *mut FlodlTensor,
793    ) -> *mut c_char;
794
795    pub fn flodl_multinomial(
796        probs: FlodlTensor, num_samples: i64, replacement: i32,
797        result: *mut FlodlTensor,
798    ) -> *mut c_char;
799
800    // --- Normalization ---
801
802    pub fn flodl_normalize(
803        t: FlodlTensor, p: f64, dim: i32, result: *mut FlodlTensor,
804    ) -> *mut c_char;
805
806    // --- Shape operations (additional) ---
807
808    pub fn flodl_chunk(
809        t: FlodlTensor, chunks: i32, dim: i32,
810        results: *mut *mut FlodlTensor, count: *mut i32,
811    ) -> *mut c_char;
812
813    pub fn flodl_repeat(
814        t: FlodlTensor, repeats: *mut i64, ndim: i32,
815        result: *mut FlodlTensor,
816    ) -> *mut c_char;
817
818    pub fn flodl_pad(
819        t: FlodlTensor, padding: *mut i64, pad_len: i32, value: f64,
820        result: *mut FlodlTensor,
821    ) -> *mut c_char;
822
823    // mode: 0=constant, 1=reflect, 2=replicate, 3=circular
824    pub fn flodl_pad_mode(
825        t: FlodlTensor, padding: *mut i64, pad_len: i32,
826        mode: i32, value: f64,
827        result: *mut FlodlTensor,
828    ) -> *mut c_char;
829
830    // mode: 0=nearest, 1=bilinear, 2=bicubic, 3=trilinear
831    pub fn flodl_interpolate(
832        input: FlodlTensor, output_size: *mut i64, ndim: i32,
833        mode: i32, align_corners: i32,
834        result: *mut FlodlTensor,
835    ) -> *mut c_char;
836
837    pub fn flodl_flip(
838        t: FlodlTensor, dims: *mut i64, ndim: i32,
839        result: *mut FlodlTensor,
840    ) -> *mut c_char;
841
842    pub fn flodl_roll(
843        t: FlodlTensor, shift: i64, dim: i32,
844        result: *mut FlodlTensor,
845    ) -> *mut c_char;
846
847    pub fn flodl_split(
848        t: FlodlTensor, split_size: i64, dim: i32,
849        results: *mut *mut FlodlTensor, count: *mut i32,
850    ) -> *mut c_char;
851
852    pub fn flodl_unbind(
853        t: FlodlTensor, dim: i32,
854        results: *mut *mut FlodlTensor, count: *mut i32,
855    ) -> *mut c_char;
856
857    pub fn flodl_contiguous(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
858    pub fn flodl_is_contiguous(t: FlodlTensor) -> i32;
859
860    pub fn flodl_argsort(
861        t: FlodlTensor, dim: i32, descending: i32,
862        result: *mut FlodlTensor,
863    ) -> *mut c_char;
864
865    pub fn flodl_scatter(
866        t: FlodlTensor, dim: i32, index: FlodlTensor, src: FlodlTensor,
867        result: *mut FlodlTensor,
868    ) -> *mut c_char;
869
870    // --- Autograd ---
871
872    pub fn flodl_set_requires_grad(
873        t: FlodlTensor, requires_grad: i32, result: *mut FlodlTensor,
874    ) -> *mut c_char;
875
876    pub fn flodl_requires_grad(t: FlodlTensor) -> i32;
877
878    /// Force creation of the AccumulateGrad node for a leaf tensor with
879    /// `requires_grad=true`. The node's stream is pinned to the current
880    /// CUDA stream at the moment of this call. Use under `StreamGuard`
881    /// to ensure DDP workers' parameters accumulate on the training
882    /// stream, not the autograd engine's default stream.
883    ///
884    /// Writes an opaque handle to `*handle_out` that keeps the node
885    /// alive. The caller must later pass it to
886    /// [`flodl_grad_accumulator_delete`] to free it. For non-leaf or
887    /// non-requires-grad tensors `*handle_out` is set to null.
888    pub fn flodl_ensure_grad_accumulator(
889        t: FlodlTensor, handle_out: *mut *mut c_void,
890    ) -> *mut c_char;
891
892    /// Free a handle returned by [`flodl_ensure_grad_accumulator`].
893    /// Safe to call with a null pointer.
894    pub fn flodl_grad_accumulator_delete(handle: *mut c_void);
895
896    pub fn flodl_backward(t: FlodlTensor) -> *mut c_char;
897
898    pub fn flodl_grad(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
899
900    pub fn flodl_set_grad(t: FlodlTensor, grad: FlodlTensor) -> *mut c_char;
901
902    pub fn flodl_zero_grad(t: FlodlTensor) -> *mut c_char;
903
904    pub fn flodl_detach(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
905
906    pub fn flodl_detach_(t: FlodlTensor) -> *mut c_char;
907
908    pub fn flodl_is_leaf(t: FlodlTensor) -> i32;
909
910    // --- Autograd context ---
911
912    pub fn flodl_no_grad_guard_new() -> *mut c_void;
913    pub fn flodl_no_grad_guard_delete(guard: *mut c_void);
914    pub fn flodl_is_grad_enabled() -> i32;
915
916    // --- Autocast (automatic mixed precision) ---
917
918    pub fn flodl_autocast_guard_new(device_type: i32, dtype: i32) -> *mut c_void;
919    pub fn flodl_autocast_guard_delete(guard: *mut c_void);
920    pub fn flodl_is_autocast_enabled(device_type: i32) -> i32;
921
922    // --- Meshgrid ---
923
924    pub fn flodl_meshgrid(
925        tensors: *mut FlodlTensor, count: i32,
926        results: *mut *mut FlodlTensor, result_count: *mut i32,
927    ) -> *mut c_char;
928
929    // --- Pairwise distance ---
930
931    pub fn flodl_cdist(
932        x: FlodlTensor, y: FlodlTensor, p: f64,
933        result: *mut FlodlTensor,
934    ) -> *mut c_char;
935
936    // --- Cosine similarity ---
937
938    pub fn flodl_cosine_similarity(
939        a: FlodlTensor, b: FlodlTensor,
940        dim: i64, eps: f64,
941        result: *mut FlodlTensor,
942    ) -> *mut c_char;
943
944    // --- Fused ops ---
945
946    pub fn flodl_linear(
947        input: FlodlTensor, weight: FlodlTensor, bias: FlodlTensor,
948        result: *mut FlodlTensor,
949    ) -> *mut c_char;
950
951    pub fn flodl_gru_cell(
952        input: FlodlTensor, hx: FlodlTensor,
953        w_ih: FlodlTensor, w_hh: FlodlTensor,
954        b_ih: FlodlTensor, b_hh: FlodlTensor,
955        result: *mut FlodlTensor,
956    ) -> *mut c_char;
957
958    pub fn flodl_lstm_cell(
959        input: FlodlTensor, hx: FlodlTensor, cx: FlodlTensor,
960        w_ih: FlodlTensor, w_hh: FlodlTensor,
961        b_ih: FlodlTensor, b_hh: FlodlTensor,
962        h_out: *mut FlodlTensor, c_out: *mut FlodlTensor,
963    ) -> *mut c_char;
964
965    // Fused sequence ops (cuDNN-accelerated)
966    pub fn flodl_lstm(
967        input: FlodlTensor, h_0: FlodlTensor, c_0: FlodlTensor,
968        params: *const FlodlTensor, num_params: i64,
969        num_layers: i64, batch_first: bool, flatten: bool,
970        output: *mut FlodlTensor, h_n: *mut FlodlTensor, c_n: *mut FlodlTensor,
971    ) -> *mut c_char;
972
973    pub fn flodl_gru(
974        input: FlodlTensor, h_0: FlodlTensor,
975        params: *const FlodlTensor, num_params: i64,
976        num_layers: i64, batch_first: bool, flatten: bool,
977        output: *mut FlodlTensor, h_n: *mut FlodlTensor,
978    ) -> *mut c_char;
979
980    // Cached RNN params (zero per-forward overhead)
981    pub fn flodl_rnn_params_create(
982        params: *const FlodlTensor, num_params: i64,
983        mode: i64, num_layers: i64, batch_first: bool, flatten: bool,
984        out: *mut *mut std::os::raw::c_void,
985    ) -> *mut c_char;
986    pub fn flodl_rnn_params_free(rp: *mut std::os::raw::c_void);
987    pub fn flodl_lstm_cached(
988        input: FlodlTensor, h_0: FlodlTensor, c_0: FlodlTensor,
989        rp: *mut std::os::raw::c_void, num_layers: i64, batch_first: bool,
990        output: *mut FlodlTensor, h_n: *mut FlodlTensor, c_n: *mut FlodlTensor,
991    ) -> *mut c_char;
992    pub fn flodl_gru_cached(
993        input: FlodlTensor, h_0: FlodlTensor,
994        rp: *mut std::os::raw::c_void, num_layers: i64, batch_first: bool,
995        output: *mut FlodlTensor, h_n: *mut FlodlTensor,
996    ) -> *mut c_char;
997
998    // --- cuDNN benchmark ---
999
1000    pub fn flodl_set_cudnn_benchmark(enable: i32);
1001
1002    // --- RNG seed ---
1003
1004    pub fn flodl_manual_seed(seed: u64);
1005    pub fn flodl_cuda_manual_seed_all(seed: u64);
1006
1007    // --- In-place operations ---
1008
1009    pub fn flodl_add_(t: FlodlTensor, other: FlodlTensor) -> *mut c_char;
1010    pub fn flodl_sub_(t: FlodlTensor, other: FlodlTensor) -> *mut c_char;
1011    pub fn flodl_mul_scalar_(t: FlodlTensor, scalar: f64) -> *mut c_char;
1012    pub fn flodl_add_scalar_(t: FlodlTensor, scalar: f64) -> *mut c_char;
1013    pub fn flodl_zero_(t: FlodlTensor) -> *mut c_char;
1014    pub fn flodl_mul_(t: FlodlTensor, other: FlodlTensor) -> *mut c_char;
1015    pub fn flodl_div_scalar_(t: FlodlTensor, scalar: f64) -> *mut c_char;
1016    pub fn flodl_div_(t: FlodlTensor, other: FlodlTensor) -> *mut c_char;
1017    pub fn flodl_fill_(t: FlodlTensor, value: f64) -> *mut c_char;
1018
1019    // --- Fused Adam step ---
1020
1021    pub fn flodl_adam_step(
1022        param: FlodlTensor, grad: FlodlTensor,
1023        m: FlodlTensor, v: FlodlTensor,
1024        lr: f64, beta1: f64, beta2: f64, eps: f64,
1025        weight_decay: f64, step: i64,
1026    ) -> *mut c_char;
1027
1028    // --- Batched Adam step ---
1029
1030    pub fn flodl_adam_step_batched(
1031        params: *mut FlodlTensor, grads: *mut FlodlTensor,
1032        ms: *mut FlodlTensor, vs: *mut FlodlTensor,
1033        lrs: *mut f64, count: i32,
1034        beta1: f64, beta2: f64, eps: f64,
1035        weight_decay: f64, step: i64,
1036    ) -> *mut c_char;
1037
1038    // --- Fused Adam/AdamW (multi-tensor kernel) ---
1039
1040    pub fn flodl_fused_adam_(
1041        params: *mut FlodlTensor, grads: *mut FlodlTensor,
1042        exp_avgs: *mut FlodlTensor, exp_avg_sqs: *mut FlodlTensor,
1043        count: i32, lr: f64,
1044        beta1: f64, beta2: f64, eps: f64,
1045        weight_decay: f64, steps: *const i64,
1046        grad_scale: FlodlTensor, found_inf: FlodlTensor,
1047    ) -> *mut c_char;
1048
1049    pub fn flodl_fused_adamw_(
1050        params: *mut FlodlTensor, grads: *mut FlodlTensor,
1051        exp_avgs: *mut FlodlTensor, exp_avg_sqs: *mut FlodlTensor,
1052        count: i32, lr: f64,
1053        beta1: f64, beta2: f64, eps: f64,
1054        weight_decay: f64, steps: *const i64,
1055        grad_scale: FlodlTensor, found_inf: FlodlTensor,
1056    ) -> *mut c_char;
1057
1058    // --- Pinned memory ---
1059
1060    pub fn flodl_pin_memory(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
1061    pub fn flodl_is_pinned(t: FlodlTensor) -> i32;
1062
1063    // --- Memory diagnostics ---
1064
1065    pub fn flodl_malloc_trim() -> i32;
1066
1067    // --- Zero grad (set_to_none) ---
1068
1069    pub fn flodl_zero_grad_set_to_none(t: FlodlTensor);
1070
1071    // --- Fused clip_grad_norm ---
1072
1073    pub fn flodl_clip_grad_norm(
1074        params: *mut FlodlTensor, count: i32,
1075        max_norm: f64, total_norm_out: *mut f64,
1076    ) -> *mut c_char;
1077
1078    // --- Multi-tensor foreach operations ---
1079
1080    pub fn flodl_foreach_add_scalar_(
1081        tensors: *mut FlodlTensor, count: i32, scalar: f64,
1082    ) -> *mut c_char;
1083
1084    pub fn flodl_foreach_mul_scalar_(
1085        tensors: *mut FlodlTensor, count: i32, scalar: f64,
1086    ) -> *mut c_char;
1087
1088    pub fn flodl_foreach_zero_(
1089        tensors: *mut FlodlTensor, count: i32,
1090    ) -> *mut c_char;
1091
1092    pub fn flodl_foreach_add_list_(
1093        tensors1: *mut FlodlTensor, tensors2: *mut FlodlTensor,
1094        count: i32, alpha: f64,
1095    ) -> *mut c_char;
1096
1097    pub fn flodl_foreach_norm(
1098        tensors: *mut FlodlTensor, count: i32, ord: f64,
1099        results: *mut FlodlTensor,
1100    ) -> *mut c_char;
1101
1102    pub fn flodl_foreach_lerp_scalar_(
1103        tensors1: *mut FlodlTensor, tensors2: *mut FlodlTensor,
1104        count: i32, weight: f64,
1105    ) -> *mut c_char;
1106
1107    pub fn flodl_foreach_sqrt_(
1108        tensors: *mut FlodlTensor, count: i32,
1109    ) -> *mut c_char;
1110
1111    // --- Autograd diagnostics ---
1112
1113    pub fn flodl_autograd_node_count(t: FlodlTensor) -> i64;
1114
1115    // --- Fused loss functions ---
1116
1117    pub fn flodl_mse_loss(
1118        pred: FlodlTensor, target: FlodlTensor,
1119        reduction: i64, result: *mut FlodlTensor,
1120    ) -> *mut c_char;
1121
1122    pub fn flodl_cross_entropy_loss(
1123        pred: FlodlTensor, target: FlodlTensor,
1124        reduction: i64, ignore_index: i64, label_smoothing: f64,
1125        result: *mut FlodlTensor,
1126    ) -> *mut c_char;
1127
1128    pub fn flodl_bce_with_logits_loss(
1129        pred: FlodlTensor, target: FlodlTensor,
1130        reduction: i64, result: *mut FlodlTensor,
1131    ) -> *mut c_char;
1132
1133    pub fn flodl_bce_loss(
1134        pred: FlodlTensor, target: FlodlTensor,
1135        reduction: i64, result: *mut FlodlTensor,
1136    ) -> *mut c_char;
1137
1138    pub fn flodl_l1_loss(
1139        pred: FlodlTensor, target: FlodlTensor,
1140        reduction: i64, result: *mut FlodlTensor,
1141    ) -> *mut c_char;
1142
1143    pub fn flodl_smooth_l1_loss(
1144        pred: FlodlTensor, target: FlodlTensor,
1145        reduction: i64, beta: f64,
1146        result: *mut FlodlTensor,
1147    ) -> *mut c_char;
1148
1149    pub fn flodl_kl_div_loss(
1150        input: FlodlTensor, target: FlodlTensor,
1151        reduction: i64, log_target: i32,
1152        result: *mut FlodlTensor,
1153    ) -> *mut c_char;
1154
1155    pub fn flodl_nll_loss(
1156        input: FlodlTensor, target: FlodlTensor,
1157        reduction: i64, ignore_index: i64,
1158        result: *mut FlodlTensor,
1159    ) -> *mut c_char;
1160
1161    pub fn flodl_ctc_loss(
1162        log_probs: FlodlTensor, targets: FlodlTensor,
1163        input_lengths: FlodlTensor, target_lengths: FlodlTensor,
1164        blank: i64, reduction: i64,
1165        result: *mut FlodlTensor,
1166    ) -> *mut c_char;
1167
1168    // --- Fused batch normalization ---
1169
1170    pub fn flodl_batch_norm(
1171        input: FlodlTensor, weight: FlodlTensor,
1172        bias: FlodlTensor, running_mean: FlodlTensor,
1173        running_var: FlodlTensor, training: i32,
1174        momentum: f64, eps: f64,
1175        result: *mut FlodlTensor,
1176    ) -> *mut c_char;
1177
1178    // --- Fused dropout ---
1179
1180    pub fn flodl_dropout(
1181        input: FlodlTensor, p: f64, training: i32,
1182        result: *mut FlodlTensor,
1183    ) -> *mut c_char;
1184
1185    pub fn flodl_feature_dropout(
1186        input: FlodlTensor, p: f64, training: i32,
1187        result: *mut FlodlTensor,
1188    ) -> *mut c_char;
1189
1190    // --- In-place copy ---
1191
1192    pub fn flodl_copy_(dst: FlodlTensor, src: FlodlTensor, non_blocking: i32) -> *mut c_char;
1193
1194    // --- Memory format ---
1195
1196    pub fn flodl_to_channels_last(t: FlodlTensor, result: *mut FlodlTensor) -> *mut c_char;
1197    pub fn flodl_is_channels_last(t: FlodlTensor) -> i32;
1198
1199    // --- Embedding lookup ---
1200
1201    pub fn flodl_embedding(
1202        weight: FlodlTensor, indices: FlodlTensor,
1203        padding_idx: i64,
1204        scale_grad_by_freq: i32, sparse: i32,
1205        result: *mut FlodlTensor,
1206    ) -> *mut c_char;
1207
1208    // --- Embedding bag ---
1209
1210    pub fn flodl_embedding_bag(
1211        weight: FlodlTensor, indices: FlodlTensor, offsets: FlodlTensor,
1212        mode: i64, result: *mut FlodlTensor,
1213    ) -> *mut c_char;
1214
1215    // --- CUDA Graphs ---
1216
1217    pub fn flodl_cuda_graph_new(graph_out: *mut *mut c_void) -> *mut c_char;
1218    pub fn flodl_cuda_graph_capture_begin(
1219        graph: *mut c_void, pool_hi: u64, pool_lo: u64, mode: i32,
1220    ) -> *mut c_char;
1221    pub fn flodl_cuda_graph_capture_end(graph: *mut c_void) -> *mut c_char;
1222    pub fn flodl_cuda_graph_replay(graph: *mut c_void) -> *mut c_char;
1223    pub fn flodl_cuda_graph_reset(graph: *mut c_void) -> *mut c_char;
1224    pub fn flodl_cuda_graph_delete(graph: *mut c_void);
1225    pub fn flodl_cuda_graph_pool(
1226        graph: *mut c_void, pool_hi: *mut u64, pool_lo: *mut u64,
1227    );
1228    pub fn flodl_cuda_graph_pool_handle(pool_hi: *mut u64, pool_lo: *mut u64);
1229
1230    // --- CUDA Events ---
1231
1232    pub fn flodl_cuda_event_new(flags: i32, event_out: *mut *mut c_void) -> *mut c_char;
1233    pub fn flodl_cuda_event_record(event: *mut c_void) -> *mut c_char;
1234    pub fn flodl_cuda_event_record_on_stream(
1235        event: *mut c_void, stream: *mut c_void,
1236    ) -> *mut c_char;
1237    pub fn flodl_cuda_event_synchronize(event: *mut c_void) -> *mut c_char;
1238    pub fn flodl_cuda_event_elapsed_time(
1239        start: *mut c_void, end: *mut c_void, ms_out: *mut f32,
1240    ) -> *mut c_char;
1241    pub fn flodl_cuda_event_query(event: *mut c_void) -> i32;
1242    pub fn flodl_cuda_event_delete(event: *mut c_void);
1243
1244    // --- CUDA Streams ---
1245
1246    pub fn flodl_cuda_stream_new(
1247        device_index: i32, high_priority: i32, stream_out: *mut *mut c_void,
1248    ) -> *mut c_char;
1249    pub fn flodl_cuda_stream_synchronize(stream: *mut c_void) -> *mut c_char;
1250    pub fn flodl_cuda_stream_wait_event(
1251        stream: *mut c_void, event: *mut c_void,
1252    ) -> *mut c_char;
1253    pub fn flodl_tensor_record_stream(
1254        tensor: *mut c_void, stream: *mut c_void,
1255    ) -> *mut c_char;
1256    pub fn flodl_cuda_stream_query(stream: *mut c_void) -> i32;
1257    pub fn flodl_cuda_stream_set_current(stream: *mut c_void);
1258    pub fn flodl_cuda_stream_get_current(device_index: i32) -> *mut c_void;
1259    pub fn flodl_cuda_stream_restore_default(device_index: i32);
1260    pub fn flodl_cuda_stream_delete(stream: *mut c_void);
1261
1262    // --- NCCL Collective Operations ---
1263
1264    pub fn flodl_nccl_init(
1265        ndev: i32, devlist: *const i32, handle_out: *mut *mut c_void,
1266    ) -> *mut c_char;
1267    pub fn flodl_nccl_destroy(handle: *mut c_void);
1268    pub fn flodl_nccl_all_reduce(
1269        handle: *mut c_void, tensors: *mut FlodlTensor,
1270        streams: *mut *mut c_void, op: i32,
1271    ) -> *mut c_char;
1272    pub fn flodl_nccl_broadcast(
1273        handle: *mut c_void, tensors: *mut FlodlTensor,
1274        streams: *mut *mut c_void, root: i32,
1275    ) -> *mut c_char;
1276    pub fn flodl_nccl_size(handle: *mut c_void) -> i32;
1277
1278    // --- NCCL Per-Rank Operations ---
1279
1280    pub fn flodl_nccl_get_unique_id(uid_out: *mut u8) -> *mut c_char;
1281    pub fn flodl_nccl_init_rank(
1282        rank: i32, nranks: i32, uid: *const u8, handle_out: *mut *mut c_void,
1283    ) -> *mut c_char;
1284    pub fn flodl_nccl_destroy_rank(handle: *mut c_void);
1285    pub fn flodl_nccl_abort_rank(handle: *mut c_void) -> *mut c_char;
1286    pub fn flodl_nccl_all_reduce_rank(
1287        handle: *mut c_void, tensors: *mut FlodlTensor, ntensors: i32,
1288        stream: *mut c_void, op: i32,
1289    ) -> *mut c_char;
1290    pub fn flodl_nccl_redop_premulsum_create_rank(
1291        handle: *mut c_void, scalar: f32, op_out: *mut i32,
1292    ) -> *mut c_char;
1293    pub fn flodl_nccl_redop_destroy_rank(handle: *mut c_void, op: i32) -> *mut c_char;
1294    pub fn flodl_nccl_broadcast_rank(
1295        handle: *mut c_void, tensors: *mut FlodlTensor, ntensors: i32,
1296        stream: *mut c_void, root: i32,
1297    ) -> *mut c_char;
1298    pub fn flodl_nccl_split_rank(
1299        group_handle: *mut c_void, rank: i32,
1300        rank_handle_out: *mut *mut c_void,
1301    ) -> *mut c_char;
1302
1303    // --- Utility ---
1304
1305    pub fn flodl_free_string(s: *mut c_char);
1306}