Skip to main content

singe_cusolver/svd/
mod.rs

1mod info;
2mod raw;
3mod validation;
4
5use singe_cuda::{
6    data_type::DataTypeLike,
7    memory::DeviceMemory,
8    types::{Complex32, Complex64},
9};
10
11use crate::{
12    context::Context,
13    error::Result,
14    layout::{
15        ByteWorkspaceMut, MatrixMut, MatrixRef, StridedBatchedMatrixMut, StridedBatchedMatrixRef,
16        StridedBatchedVectorMut, StridedBatchedVectorRef, WorkspaceSizes,
17    },
18    params::Params,
19    types::{EigenMode, SvdMode, TruncatedSvdMode},
20};
21
22use raw::*;
23
24pub use info::GesvdjInfo;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct Gesvd {
28    pub job_u: SvdMode,
29    pub job_vt: SvdMode,
30    pub rows: usize,
31    pub columns: usize,
32}
33
34impl Gesvd {
35    pub fn new(job_u: SvdMode, job_vt: SvdMode, rows: usize, columns: usize) -> Self {
36        Self {
37            job_u,
38            job_vt,
39            rows,
40            columns,
41        }
42    }
43
44    pub fn workspace_size<
45        TA: DataTypeLike,
46        TS: DataTypeLike,
47        TU: DataTypeLike,
48        TVT: DataTypeLike,
49    >(
50        self,
51        ctx: &Context,
52        params: &Params,
53        input: GesvdInput<'_, TA, TS, TU, TVT>,
54    ) -> Result<WorkspaceSizes> {
55        xgesvd_buffer_size(
56            ctx,
57            params,
58            self.job_u,
59            self.job_vt,
60            self.rows,
61            self.columns,
62            input.a,
63            input.singular_values,
64            input.left_vectors,
65            input.right_vectors_transposed,
66        )
67    }
68
69    pub fn execute<TA: DataTypeLike, TS: DataTypeLike, TU: DataTypeLike, TVT: DataTypeLike>(
70        self,
71        ctx: &Context,
72        params: &Params,
73        bindings: GesvdBindings<'_, TA, TS, TU, TVT>,
74    ) -> Result<()> {
75        xgesvd(
76            ctx,
77            params,
78            self.job_u,
79            self.job_vt,
80            self.rows,
81            self.columns,
82            bindings.a,
83            bindings.singular_values,
84            bindings.left_vectors,
85            bindings.right_vectors_transposed,
86            bindings.workspace,
87            bindings.dev_info,
88        )
89    }
90}
91
92#[derive(Debug, Clone, Copy)]
93pub struct GesvdInput<'a, TA, TS, TU, TVT> {
94    pub a: MatrixRef<'a, TA>,
95    pub singular_values: &'a DeviceMemory<TS>,
96    pub left_vectors: Option<MatrixRef<'a, TU>>,
97    pub right_vectors_transposed: Option<MatrixRef<'a, TVT>>,
98}
99
100#[derive(Debug)]
101pub struct GesvdBindings<'a, TA, TS, TU, TVT> {
102    pub a: MatrixMut<'a, TA>,
103    pub singular_values: &'a mut DeviceMemory<TS>,
104    pub left_vectors: Option<MatrixMut<'a, TU>>,
105    pub right_vectors_transposed: Option<MatrixMut<'a, TVT>>,
106    pub workspace: ByteWorkspaceMut<'a>,
107    pub dev_info: &'a mut DeviceMemory<i32>,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub struct Gesvdp {
112    pub mode: EigenMode,
113    pub economy: bool,
114    pub rows: usize,
115    pub columns: usize,
116}
117
118impl Gesvdp {
119    pub fn new(mode: EigenMode, economy: bool, rows: usize, columns: usize) -> Self {
120        Self {
121            mode,
122            economy,
123            rows,
124            columns,
125        }
126    }
127
128    pub fn workspace_size<
129        TA: DataTypeLike,
130        TS: DataTypeLike,
131        TU: DataTypeLike,
132        TV: DataTypeLike,
133    >(
134        self,
135        ctx: &Context,
136        params: &Params,
137        input: GesvdpInput<'_, TA, TS, TU, TV>,
138    ) -> Result<WorkspaceSizes> {
139        xgesvdp_buffer_size(
140            ctx,
141            params,
142            self.mode,
143            self.economy,
144            self.rows,
145            self.columns,
146            input.a,
147            input.singular_values,
148            input.left_vectors,
149            input.right_vectors,
150        )
151    }
152
153    pub fn execute<TA: DataTypeLike, TS: DataTypeLike, TU: DataTypeLike, TV: DataTypeLike>(
154        self,
155        ctx: &Context,
156        params: &Params,
157        bindings: GesvdpBindings<'_, TA, TS, TU, TV>,
158    ) -> Result<()> {
159        xgesvdp(
160            ctx,
161            params,
162            self.mode,
163            self.economy,
164            self.rows,
165            self.columns,
166            bindings.a,
167            bindings.singular_values,
168            bindings.left_vectors,
169            bindings.right_vectors,
170            bindings.workspace,
171            bindings.dev_info,
172            bindings.residual,
173        )
174    }
175}
176
177#[derive(Debug, Clone, Copy)]
178pub struct GesvdpInput<'a, TA, TS, TU, TV> {
179    pub a: MatrixRef<'a, TA>,
180    pub singular_values: &'a DeviceMemory<TS>,
181    pub left_vectors: Option<MatrixRef<'a, TU>>,
182    pub right_vectors: Option<MatrixRef<'a, TV>>,
183}
184
185#[derive(Debug)]
186pub struct GesvdpBindings<'a, TA, TS, TU, TV> {
187    pub a: MatrixMut<'a, TA>,
188    pub singular_values: &'a mut DeviceMemory<TS>,
189    pub left_vectors: Option<MatrixMut<'a, TU>>,
190    pub right_vectors: Option<MatrixMut<'a, TV>>,
191    pub workspace: ByteWorkspaceMut<'a>,
192    pub dev_info: &'a mut DeviceMemory<i32>,
193    pub residual: Option<&'a mut f64>,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub struct Gesvdr {
198    pub left_vectors: TruncatedSvdMode,
199    pub right_vectors: TruncatedSvdMode,
200    pub rows: usize,
201    pub columns: usize,
202    pub rank: usize,
203    pub oversamples: usize,
204    pub iterations: usize,
205}
206
207impl Gesvdr {
208    pub fn new(
209        left_vectors: TruncatedSvdMode,
210        right_vectors: TruncatedSvdMode,
211        rows: usize,
212        columns: usize,
213        rank: usize,
214        oversamples: usize,
215        iterations: usize,
216    ) -> Self {
217        Self {
218            left_vectors,
219            right_vectors,
220            rows,
221            columns,
222            rank,
223            oversamples,
224            iterations,
225        }
226    }
227
228    pub fn workspace_size<
229        TA: DataTypeLike,
230        TS: DataTypeLike,
231        TU: DataTypeLike,
232        TV: DataTypeLike,
233    >(
234        self,
235        ctx: &Context,
236        params: &Params,
237        input: GesvdrInput<'_, TA, TS, TU, TV>,
238    ) -> Result<WorkspaceSizes> {
239        xgesvdr_buffer_size(
240            ctx,
241            params,
242            self.left_vectors,
243            self.right_vectors,
244            self.rows,
245            self.columns,
246            self.rank,
247            self.oversamples,
248            self.iterations,
249            input.a,
250            input.singular_values,
251            input.left_vectors,
252            input.right_vectors,
253        )
254    }
255
256    pub fn execute<TA: DataTypeLike, TS: DataTypeLike, TU: DataTypeLike, TV: DataTypeLike>(
257        self,
258        ctx: &Context,
259        params: &Params,
260        bindings: GesvdrBindings<'_, TA, TS, TU, TV>,
261    ) -> Result<()> {
262        xgesvdr(
263            ctx,
264            params,
265            self.left_vectors,
266            self.right_vectors,
267            self.rows,
268            self.columns,
269            self.rank,
270            self.oversamples,
271            self.iterations,
272            bindings.a,
273            bindings.singular_values,
274            bindings.left_vectors,
275            bindings.right_vectors,
276            bindings.workspace,
277            bindings.dev_info,
278        )
279    }
280}
281
282#[derive(Debug, Clone, Copy)]
283pub struct GesvdrInput<'a, TA, TS, TU, TV> {
284    pub a: MatrixRef<'a, TA>,
285    pub singular_values: &'a DeviceMemory<TS>,
286    pub left_vectors: Option<MatrixRef<'a, TU>>,
287    pub right_vectors: Option<MatrixRef<'a, TV>>,
288}
289
290#[derive(Debug)]
291pub struct GesvdrBindings<'a, TA, TS, TU, TV> {
292    pub a: MatrixMut<'a, TA>,
293    pub singular_values: &'a mut DeviceMemory<TS>,
294    pub left_vectors: Option<MatrixMut<'a, TU>>,
295    pub right_vectors: Option<MatrixMut<'a, TV>>,
296    pub workspace: ByteWorkspaceMut<'a>,
297    pub dev_info: &'a mut DeviceMemory<i32>,
298}
299
300#[derive(Debug, Clone, Copy, PartialEq, Eq)]
301pub struct Gesvdj {
302    pub mode: EigenMode,
303    pub economy: bool,
304    pub rows: usize,
305    pub columns: usize,
306}
307
308impl Gesvdj {
309    pub fn new(mode: EigenMode, economy: bool, rows: usize, columns: usize) -> Self {
310        Self {
311            mode,
312            economy,
313            rows,
314            columns,
315        }
316    }
317
318    pub fn workspace_size_f32(
319        self,
320        ctx: &Context,
321        input: GesvdjInput<'_, f32, f32>,
322        params: &GesvdjInfo,
323    ) -> Result<usize> {
324        sgesvdj_buffer_size(
325            ctx,
326            self.mode,
327            self.economy,
328            self.rows,
329            self.columns,
330            input.a,
331            input.singular_values,
332            input.left_vectors,
333            input.right_vectors,
334            params,
335        )
336    }
337
338    pub fn execute_f32(
339        self,
340        ctx: &Context,
341        bindings: GesvdjBindings<'_, f32, f32>,
342        params: &GesvdjInfo,
343    ) -> Result<()> {
344        sgesvdj(
345            ctx,
346            self.mode,
347            self.economy,
348            self.rows,
349            self.columns,
350            bindings.a,
351            bindings.singular_values,
352            bindings.left_vectors,
353            bindings.right_vectors,
354            bindings.workspace,
355            bindings.dev_info,
356            params,
357        )
358    }
359
360    pub fn workspace_size_f64(
361        self,
362        ctx: &Context,
363        input: GesvdjInput<'_, f64, f64>,
364        params: &GesvdjInfo,
365    ) -> Result<usize> {
366        dgesvdj_buffer_size(
367            ctx,
368            self.mode,
369            self.economy,
370            self.rows,
371            self.columns,
372            input.a,
373            input.singular_values,
374            input.left_vectors,
375            input.right_vectors,
376            params,
377        )
378    }
379
380    pub fn execute_f64(
381        self,
382        ctx: &Context,
383        bindings: GesvdjBindings<'_, f64, f64>,
384        params: &GesvdjInfo,
385    ) -> Result<()> {
386        dgesvdj(
387            ctx,
388            self.mode,
389            self.economy,
390            self.rows,
391            self.columns,
392            bindings.a,
393            bindings.singular_values,
394            bindings.left_vectors,
395            bindings.right_vectors,
396            bindings.workspace,
397            bindings.dev_info,
398            params,
399        )
400    }
401
402    pub fn workspace_size_complex_f32(
403        self,
404        ctx: &Context,
405        input: GesvdjInput<'_, Complex32, f32>,
406        params: &GesvdjInfo,
407    ) -> Result<usize> {
408        cgesvdj_buffer_size(
409            ctx,
410            self.mode,
411            self.economy,
412            self.rows,
413            self.columns,
414            input.a,
415            input.singular_values,
416            input.left_vectors,
417            input.right_vectors,
418            params,
419        )
420    }
421
422    pub fn execute_complex_f32(
423        self,
424        ctx: &Context,
425        bindings: GesvdjBindings<'_, Complex32, f32>,
426        params: &GesvdjInfo,
427    ) -> Result<()> {
428        cgesvdj(
429            ctx,
430            self.mode,
431            self.economy,
432            self.rows,
433            self.columns,
434            bindings.a,
435            bindings.singular_values,
436            bindings.left_vectors,
437            bindings.right_vectors,
438            bindings.workspace,
439            bindings.dev_info,
440            params,
441        )
442    }
443
444    pub fn workspace_size_complex_f64(
445        self,
446        ctx: &Context,
447        input: GesvdjInput<'_, Complex64, f64>,
448        params: &GesvdjInfo,
449    ) -> Result<usize> {
450        zgesvdj_buffer_size(
451            ctx,
452            self.mode,
453            self.economy,
454            self.rows,
455            self.columns,
456            input.a,
457            input.singular_values,
458            input.left_vectors,
459            input.right_vectors,
460            params,
461        )
462    }
463
464    pub fn execute_complex_f64(
465        self,
466        ctx: &Context,
467        bindings: GesvdjBindings<'_, Complex64, f64>,
468        params: &GesvdjInfo,
469    ) -> Result<()> {
470        zgesvdj(
471            ctx,
472            self.mode,
473            self.economy,
474            self.rows,
475            self.columns,
476            bindings.a,
477            bindings.singular_values,
478            bindings.left_vectors,
479            bindings.right_vectors,
480            bindings.workspace,
481            bindings.dev_info,
482            params,
483        )
484    }
485}
486
487#[derive(Debug, Clone, Copy)]
488pub struct GesvdjInput<'a, TA, TS> {
489    pub a: MatrixRef<'a, TA>,
490    pub singular_values: &'a DeviceMemory<TS>,
491    pub left_vectors: Option<MatrixRef<'a, TA>>,
492    pub right_vectors: Option<MatrixRef<'a, TA>>,
493}
494
495#[derive(Debug)]
496pub struct GesvdjBindings<'a, TA, TS> {
497    pub a: MatrixMut<'a, TA>,
498    pub singular_values: &'a mut DeviceMemory<TS>,
499    pub left_vectors: Option<MatrixMut<'a, TA>>,
500    pub right_vectors: Option<MatrixMut<'a, TA>>,
501    pub workspace: &'a mut DeviceMemory<TA>,
502    pub dev_info: &'a mut DeviceMemory<i32>,
503}
504
505#[derive(Debug, Clone, Copy, PartialEq, Eq)]
506pub struct GesvdjBatched {
507    pub mode: EigenMode,
508    pub rows: usize,
509    pub columns: usize,
510    pub batch_size: usize,
511}
512
513impl GesvdjBatched {
514    pub fn new(mode: EigenMode, rows: usize, columns: usize, batch_size: usize) -> Self {
515        Self {
516            mode,
517            rows,
518            columns,
519            batch_size,
520        }
521    }
522
523    pub fn workspace_size_f32(
524        self,
525        ctx: &Context,
526        input: GesvdjInput<'_, f32, f32>,
527        params: &GesvdjInfo,
528    ) -> Result<usize> {
529        sgesvdj_batched_buffer_size(
530            ctx,
531            self.mode,
532            self.rows,
533            self.columns,
534            input.a,
535            input.singular_values,
536            input.left_vectors,
537            input.right_vectors,
538            params,
539            self.batch_size,
540        )
541    }
542
543    pub fn execute_f32(
544        self,
545        ctx: &Context,
546        bindings: GesvdjBindings<'_, f32, f32>,
547        params: &GesvdjInfo,
548    ) -> Result<()> {
549        sgesvdj_batched(
550            ctx,
551            self.mode,
552            self.rows,
553            self.columns,
554            bindings.a,
555            bindings.singular_values,
556            bindings.left_vectors,
557            bindings.right_vectors,
558            bindings.workspace,
559            bindings.dev_info,
560            params,
561            self.batch_size,
562        )
563    }
564
565    pub fn workspace_size_f64(
566        self,
567        ctx: &Context,
568        input: GesvdjInput<'_, f64, f64>,
569        params: &GesvdjInfo,
570    ) -> Result<usize> {
571        dgesvdj_batched_buffer_size(
572            ctx,
573            self.mode,
574            self.rows,
575            self.columns,
576            input.a,
577            input.singular_values,
578            input.left_vectors,
579            input.right_vectors,
580            params,
581            self.batch_size,
582        )
583    }
584
585    pub fn execute_f64(
586        self,
587        ctx: &Context,
588        bindings: GesvdjBindings<'_, f64, f64>,
589        params: &GesvdjInfo,
590    ) -> Result<()> {
591        dgesvdj_batched(
592            ctx,
593            self.mode,
594            self.rows,
595            self.columns,
596            bindings.a,
597            bindings.singular_values,
598            bindings.left_vectors,
599            bindings.right_vectors,
600            bindings.workspace,
601            bindings.dev_info,
602            params,
603            self.batch_size,
604        )
605    }
606
607    pub fn workspace_size_complex_f32(
608        self,
609        ctx: &Context,
610        input: GesvdjInput<'_, Complex32, f32>,
611        params: &GesvdjInfo,
612    ) -> Result<usize> {
613        cgesvdj_batched_buffer_size(
614            ctx,
615            self.mode,
616            self.rows,
617            self.columns,
618            input.a,
619            input.singular_values,
620            input.left_vectors,
621            input.right_vectors,
622            params,
623            self.batch_size,
624        )
625    }
626
627    pub fn execute_complex_f32(
628        self,
629        ctx: &Context,
630        bindings: GesvdjBindings<'_, Complex32, f32>,
631        params: &GesvdjInfo,
632    ) -> Result<()> {
633        cgesvdj_batched(
634            ctx,
635            self.mode,
636            self.rows,
637            self.columns,
638            bindings.a,
639            bindings.singular_values,
640            bindings.left_vectors,
641            bindings.right_vectors,
642            bindings.workspace,
643            bindings.dev_info,
644            params,
645            self.batch_size,
646        )
647    }
648
649    pub fn workspace_size_complex_f64(
650        self,
651        ctx: &Context,
652        input: GesvdjInput<'_, Complex64, f64>,
653        params: &GesvdjInfo,
654    ) -> Result<usize> {
655        zgesvdj_batched_buffer_size(
656            ctx,
657            self.mode,
658            self.rows,
659            self.columns,
660            input.a,
661            input.singular_values,
662            input.left_vectors,
663            input.right_vectors,
664            params,
665            self.batch_size,
666        )
667    }
668
669    pub fn execute_complex_f64(
670        self,
671        ctx: &Context,
672        bindings: GesvdjBindings<'_, Complex64, f64>,
673        params: &GesvdjInfo,
674    ) -> Result<()> {
675        zgesvdj_batched(
676            ctx,
677            self.mode,
678            self.rows,
679            self.columns,
680            bindings.a,
681            bindings.singular_values,
682            bindings.left_vectors,
683            bindings.right_vectors,
684            bindings.workspace,
685            bindings.dev_info,
686            params,
687            self.batch_size,
688        )
689    }
690}
691
692#[derive(Debug, Clone, Copy, PartialEq, Eq)]
693pub struct GesvdaStridedBatched {
694    pub mode: EigenMode,
695    pub rank: usize,
696    pub rows: usize,
697    pub columns: usize,
698    pub batch_size: usize,
699}
700
701impl GesvdaStridedBatched {
702    pub fn new(
703        mode: EigenMode,
704        rank: usize,
705        rows: usize,
706        columns: usize,
707        batch_size: usize,
708    ) -> Self {
709        Self {
710            mode,
711            rank,
712            rows,
713            columns,
714            batch_size,
715        }
716    }
717
718    pub fn workspace_size_f32(
719        self,
720        ctx: &Context,
721        input: GesvdaStridedBatchedInput<'_, f32, f32>,
722    ) -> Result<usize> {
723        sgesvda_strided_batched_buffer_size(
724            ctx,
725            self.mode,
726            self.rank,
727            self.rows,
728            self.columns,
729            input.a,
730            input.singular_values,
731            input.left_vectors,
732            input.right_vectors,
733            self.batch_size,
734        )
735    }
736
737    pub fn execute_f32(
738        self,
739        ctx: &Context,
740        bindings: GesvdaStridedBatchedBindings<'_, f32, f32>,
741    ) -> Result<()> {
742        sgesvda_strided_batched(
743            ctx,
744            self.mode,
745            self.rank,
746            self.rows,
747            self.columns,
748            bindings.a,
749            bindings.singular_values,
750            bindings.left_vectors,
751            bindings.right_vectors,
752            bindings.workspace,
753            bindings.dev_info,
754            bindings.residual,
755            self.batch_size,
756        )
757    }
758
759    pub fn workspace_size_f64(
760        self,
761        ctx: &Context,
762        input: GesvdaStridedBatchedInput<'_, f64, f64>,
763    ) -> Result<usize> {
764        dgesvda_strided_batched_buffer_size(
765            ctx,
766            self.mode,
767            self.rank,
768            self.rows,
769            self.columns,
770            input.a,
771            input.singular_values,
772            input.left_vectors,
773            input.right_vectors,
774            self.batch_size,
775        )
776    }
777
778    pub fn execute_f64(
779        self,
780        ctx: &Context,
781        bindings: GesvdaStridedBatchedBindings<'_, f64, f64>,
782    ) -> Result<()> {
783        dgesvda_strided_batched(
784            ctx,
785            self.mode,
786            self.rank,
787            self.rows,
788            self.columns,
789            bindings.a,
790            bindings.singular_values,
791            bindings.left_vectors,
792            bindings.right_vectors,
793            bindings.workspace,
794            bindings.dev_info,
795            bindings.residual,
796            self.batch_size,
797        )
798    }
799
800    pub fn workspace_size_complex_f32(
801        self,
802        ctx: &Context,
803        input: GesvdaStridedBatchedInput<'_, Complex32, f32>,
804    ) -> Result<usize> {
805        cgesvda_strided_batched_buffer_size(
806            ctx,
807            self.mode,
808            self.rank,
809            self.rows,
810            self.columns,
811            input.a,
812            input.singular_values,
813            input.left_vectors,
814            input.right_vectors,
815            self.batch_size,
816        )
817    }
818
819    pub fn execute_complex_f32(
820        self,
821        ctx: &Context,
822        bindings: GesvdaStridedBatchedBindings<'_, Complex32, f32>,
823    ) -> Result<()> {
824        cgesvda_strided_batched(
825            ctx,
826            self.mode,
827            self.rank,
828            self.rows,
829            self.columns,
830            bindings.a,
831            bindings.singular_values,
832            bindings.left_vectors,
833            bindings.right_vectors,
834            bindings.workspace,
835            bindings.dev_info,
836            bindings.residual,
837            self.batch_size,
838        )
839    }
840
841    pub fn workspace_size_complex_f64(
842        self,
843        ctx: &Context,
844        input: GesvdaStridedBatchedInput<'_, Complex64, f64>,
845    ) -> Result<usize> {
846        zgesvda_strided_batched_buffer_size(
847            ctx,
848            self.mode,
849            self.rank,
850            self.rows,
851            self.columns,
852            input.a,
853            input.singular_values,
854            input.left_vectors,
855            input.right_vectors,
856            self.batch_size,
857        )
858    }
859
860    pub fn execute_complex_f64(
861        self,
862        ctx: &Context,
863        bindings: GesvdaStridedBatchedBindings<'_, Complex64, f64>,
864    ) -> Result<()> {
865        zgesvda_strided_batched(
866            ctx,
867            self.mode,
868            self.rank,
869            self.rows,
870            self.columns,
871            bindings.a,
872            bindings.singular_values,
873            bindings.left_vectors,
874            bindings.right_vectors,
875            bindings.workspace,
876            bindings.dev_info,
877            bindings.residual,
878            self.batch_size,
879        )
880    }
881}
882
883#[derive(Debug, Clone, Copy)]
884pub struct GesvdaStridedBatchedInput<'a, TA, TS> {
885    pub a: StridedBatchedMatrixRef<'a, TA>,
886    pub singular_values: StridedBatchedVectorRef<'a, TS>,
887    pub left_vectors: Option<StridedBatchedMatrixRef<'a, TA>>,
888    pub right_vectors: Option<StridedBatchedMatrixRef<'a, TA>>,
889}
890
891#[derive(Debug)]
892pub struct GesvdaStridedBatchedBindings<'a, TA, TS> {
893    pub a: StridedBatchedMatrixRef<'a, TA>,
894    pub singular_values: StridedBatchedVectorMut<'a, TS>,
895    pub left_vectors: Option<StridedBatchedMatrixMut<'a, TA>>,
896    pub right_vectors: Option<StridedBatchedMatrixMut<'a, TA>>,
897    pub workspace: &'a mut DeviceMemory<TA>,
898    pub dev_info: &'a mut DeviceMemory<i32>,
899    pub residual: Option<&'a mut f64>,
900}
901
902#[cfg(all(test, feature = "testing"))]
903mod tests {
904    use singe_core::assert_close;
905    use singe_cuda::memory::DeviceMemory;
906
907    use super::*;
908    use crate::{params::Params, testing::setup_context_if_available};
909
910    #[test]
911    fn gesvd_descriptor_returns_expected_singular_values() -> Result<()> {
912        let Some(ctx) = setup_context_if_available()? else {
913            return Ok(());
914        };
915        let params = Params::create()?;
916
917        let mut a = DeviceMemory::from_slice(&[
918            3.0_f32, 0.0, //
919            0.0, 2.0,
920        ])?;
921        let mut s = DeviceMemory::<f32>::create(2)?;
922        let operation = Gesvd::new(SvdMode::None, SvdMode::None, 2, 2);
923        let workspace_sizes = operation.workspace_size(
924            &ctx,
925            &params,
926            GesvdInput {
927                a: MatrixRef::new(&a, 2),
928                singular_values: &s,
929                left_vectors: None::<MatrixRef<'_, f32>>,
930                right_vectors_transposed: None::<MatrixRef<'_, f32>>,
931            },
932        )?;
933        let mut workspace = DeviceMemory::<u8>::create(workspace_sizes.device_bytes)?;
934        let mut host_workspace = vec![0_u8; workspace_sizes.host_bytes];
935        let mut dev_info = DeviceMemory::create(1)?;
936
937        operation.execute(
938            &ctx,
939            &params,
940            GesvdBindings {
941                a: MatrixMut::new(&mut a, 2),
942                singular_values: &mut s,
943                left_vectors: None::<MatrixMut<'_, f32>>,
944                right_vectors_transposed: None::<MatrixMut<'_, f32>>,
945                workspace: ByteWorkspaceMut::new(&mut workspace, &mut host_workspace),
946                dev_info: &mut dev_info,
947            },
948        )?;
949
950        let singular_values = s.copy_to_host_vec()?;
951        let info = dev_info.copy_to_host_vec()?;
952
953        assert_eq!(info, vec![0]);
954        assert_close!(&singular_values, &[3.0, 2.0], 1.0e-5);
955        Ok(())
956    }
957
958    #[test]
959    fn gesvdp_descriptor_preserves_operation_shape() {
960        let operation = Gesvdp::new(EigenMode::Vector, true, 32, 16);
961
962        assert_eq!(operation.mode, EigenMode::Vector);
963        assert!(operation.economy);
964        assert_eq!(operation.rows, 32);
965        assert_eq!(operation.columns, 16);
966    }
967
968    #[test]
969    fn gesvdr_descriptor_preserves_operation_shape() {
970        let operation = Gesvdr::new(
971            TruncatedSvdMode::Some,
972            TruncatedSvdMode::None,
973            128,
974            64,
975            12,
976            24,
977            3,
978        );
979
980        assert_eq!(operation.left_vectors, TruncatedSvdMode::Some);
981        assert_eq!(operation.right_vectors, TruncatedSvdMode::None);
982        assert_eq!(operation.rows, 128);
983        assert_eq!(operation.columns, 64);
984        assert_eq!(operation.rank, 12);
985        assert_eq!(operation.oversamples, 24);
986        assert_eq!(operation.iterations, 3);
987    }
988
989    #[test]
990    fn test_xgesvd_returns_expected_singular_values() -> Result<()> {
991        let Some(ctx) = setup_context_if_available()? else {
992            return Ok(());
993        };
994        let params = Params::create()?;
995
996        let mut a = DeviceMemory::from_slice(&[
997            3.0_f32, 0.0, //
998            0.0, 2.0,
999        ])?;
1000        let mut s = DeviceMemory::create(2)?;
1001        let workspace_sizes = xgesvd_buffer_size::<f32, f32, f32, f32>(
1002            &ctx,
1003            &params,
1004            SvdMode::None,
1005            SvdMode::None,
1006            2,
1007            2,
1008            MatrixRef::new(&a, 2),
1009            &s,
1010            None,
1011            None,
1012        )?;
1013        let mut device_workspace = DeviceMemory::create(workspace_sizes.device_bytes.max(1))?;
1014        let mut host_workspace = vec![0_u8; workspace_sizes.host_bytes.max(1)];
1015        let mut dev_info = DeviceMemory::create(1)?;
1016
1017        xgesvd::<f32, f32, f32, f32>(
1018            &ctx,
1019            &params,
1020            SvdMode::None,
1021            SvdMode::None,
1022            2,
1023            2,
1024            MatrixMut::new(&mut a, 2),
1025            &mut s,
1026            None,
1027            None,
1028            ByteWorkspaceMut::new(&mut device_workspace, &mut host_workspace),
1029            &mut dev_info,
1030        )?;
1031
1032        let singular_values = s.copy_to_host_vec()?;
1033        let info = dev_info.copy_to_host_vec()?;
1034
1035        assert_eq!(info, vec![0]);
1036        assert_close!(&singular_values, &[3.0, 2.0], 1.0e-5);
1037        Ok(())
1038    }
1039}