Skip to main content

singe_cusolver/dense/legacy/
tridiagonal.rs

1use singe_cuda::{
2    memory::DeviceMemory,
3    types::{Complex32, Complex64},
4};
5
6use crate::{
7    context::Context,
8    dense::validation::{
9        require_info_buffer, require_workspace, validate_orgtr_inputs, validate_ormtr_inputs,
10        validate_sytrd_inputs,
11    },
12    error::Result,
13    sys, try_ffi,
14    types::{FillMode, Operation, SideMode},
15    utility::{to_i32, to_usize},
16};
17
18pub fn ssytrd_buffer_size(
19    ctx: &Context,
20    fill_mode: FillMode,
21    n: usize,
22    a: &DeviceMemory<f32>,
23    lda: usize,
24    d: &DeviceMemory<f32>,
25    e: &DeviceMemory<f32>,
26    tau: &DeviceMemory<f32>,
27) -> Result<usize> {
28    ctx.bind()?;
29    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
30    let mut lwork = 0;
31    unsafe {
32        try_ffi!(sys::cusolverDnSsytrd_bufferSize(
33            ctx.as_raw(),
34            fill_mode.into(),
35            to_i32(n, "n")?,
36            a.as_ptr().cast(),
37            to_i32(lda, "lda")?,
38            d.as_ptr().cast(),
39            e.as_ptr().cast(),
40            tau.as_ptr().cast(),
41            &raw mut lwork,
42        ))?;
43    }
44    to_usize(lwork, "lwork")
45}
46
47pub fn dsytrd_buffer_size(
48    ctx: &Context,
49    fill_mode: FillMode,
50    n: usize,
51    a: &DeviceMemory<f64>,
52    lda: usize,
53    d: &DeviceMemory<f64>,
54    e: &DeviceMemory<f64>,
55    tau: &DeviceMemory<f64>,
56) -> Result<usize> {
57    ctx.bind()?;
58    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
59    let mut lwork = 0;
60    unsafe {
61        try_ffi!(sys::cusolverDnDsytrd_bufferSize(
62            ctx.as_raw(),
63            fill_mode.into(),
64            to_i32(n, "n")?,
65            a.as_ptr().cast(),
66            to_i32(lda, "lda")?,
67            d.as_ptr().cast(),
68            e.as_ptr().cast(),
69            tau.as_ptr().cast(),
70            &raw mut lwork,
71        ))?;
72    }
73    to_usize(lwork, "lwork")
74}
75
76pub fn chetrd_buffer_size(
77    ctx: &Context,
78    fill_mode: FillMode,
79    n: usize,
80    a: &DeviceMemory<Complex32>,
81    lda: usize,
82    d: &DeviceMemory<f32>,
83    e: &DeviceMemory<f32>,
84    tau: &DeviceMemory<Complex32>,
85) -> Result<usize> {
86    ctx.bind()?;
87    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
88    let mut lwork = 0;
89    unsafe {
90        try_ffi!(sys::cusolverDnChetrd_bufferSize(
91            ctx.as_raw(),
92            fill_mode.into(),
93            to_i32(n, "n")?,
94            a.as_ptr().cast(),
95            to_i32(lda, "lda")?,
96            d.as_ptr().cast(),
97            e.as_ptr().cast(),
98            tau.as_ptr().cast(),
99            &raw mut lwork,
100        ))?;
101    }
102    to_usize(lwork, "lwork")
103}
104
105pub fn zhetrd_buffer_size(
106    ctx: &Context,
107    fill_mode: FillMode,
108    n: usize,
109    a: &DeviceMemory<Complex64>,
110    lda: usize,
111    d: &DeviceMemory<f64>,
112    e: &DeviceMemory<f64>,
113    tau: &DeviceMemory<Complex64>,
114) -> Result<usize> {
115    ctx.bind()?;
116    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
117    let mut lwork = 0;
118    unsafe {
119        try_ffi!(sys::cusolverDnZhetrd_bufferSize(
120            ctx.as_raw(),
121            fill_mode.into(),
122            to_i32(n, "n")?,
123            a.as_ptr().cast(),
124            to_i32(lda, "lda")?,
125            d.as_ptr().cast(),
126            e.as_ptr().cast(),
127            tau.as_ptr().cast(),
128            &raw mut lwork,
129        ))?;
130    }
131    to_usize(lwork, "lwork")
132}
133
134/// Use the matching buffer-size helper to calculate the required workspace size.
135///
136/// The S and D data types are real valued single and double precision, respectively.
137///
138/// The C and Z data types are complex valued single and double precision, respectively.
139///
140/// Reduces a general symmetric (Hermitian) $n \times n$ matrix `A` to the
141/// real symmetric tridiagonal form `T` by an orthogonal transformation:
142/// $Q^{H}\cdot A\cdot Q = T$.
143///
144/// On output, `A` contains `T` and Householder reflection vectors.
145/// If `fill_mode` is [`FillMode::Upper`], the diagonal and first
146/// superdiagonal of `A` are overwritten by `T`; elements above the first
147/// superdiagonal, together with `tau`, represent `Q`.
148/// If `fill_mode` is [`FillMode::Lower`], the diagonal and first subdiagonal
149/// of `A` are overwritten by `T`; elements below the first subdiagonal,
150/// together with `tau`, represent `Q`.
151///
152/// Provide workspace through `workspace`.
153/// Use the corresponding `*_buffer_size` helper to query the required workspace length.
154/// The workspace size in bytes is `size_of::<T>() * lwork`.
155///
156/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
157/// The problem size `n` is limited by `n * lda <= INT32_MAX` primarily due to the current implementation constraints.
158///
159/// # Errors
160///
161/// Returns an error if cuSOLVER has not been initialized, if the
162/// matrix dimensions, leading dimension, or fill mode are invalid, if the
163/// current GPU architecture is unsupported, or if cuSOLVER reports an
164/// internal failure.
165pub fn ssytrd(
166    ctx: &Context,
167    fill_mode: FillMode,
168    n: usize,
169    a: &mut DeviceMemory<f32>,
170    lda: usize,
171    d: &mut DeviceMemory<f32>,
172    e: &mut DeviceMemory<f32>,
173    tau: &mut DeviceMemory<f32>,
174    workspace: &mut DeviceMemory<f32>,
175    dev_info: &mut DeviceMemory<i32>,
176) -> Result<()> {
177    ctx.bind()?;
178    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
179    require_info_buffer(dev_info)?;
180    let lwork = ssytrd_buffer_size(ctx, fill_mode, n, a, lda, d, e, tau)?;
181    require_workspace(workspace.len(), lwork)?;
182    unsafe {
183        try_ffi!(sys::cusolverDnSsytrd(
184            ctx.as_raw(),
185            fill_mode.into(),
186            to_i32(n, "n")?,
187            a.as_mut_ptr().cast(),
188            to_i32(lda, "lda")?,
189            d.as_mut_ptr().cast(),
190            e.as_mut_ptr().cast(),
191            tau.as_mut_ptr().cast(),
192            workspace.as_mut_ptr().cast(),
193            to_i32(lwork, "lwork")?,
194            dev_info.as_mut_ptr().cast(),
195        ))?;
196    }
197    Ok(())
198}
199
200/// Use the matching buffer-size helper to calculate the required workspace size.
201///
202/// The S and D data types are real valued single and double precision, respectively.
203///
204/// The C and Z data types are complex valued single and double precision, respectively.
205///
206/// Reduces a general symmetric (Hermitian) $n \times n$ matrix `A` to the
207/// real symmetric tridiagonal form `T` by an orthogonal transformation:
208/// $Q^{H}\cdot A\cdot Q = T$.
209///
210/// On output, `A` contains `T` and Householder reflection vectors.
211/// If `fill_mode` is [`FillMode::Upper`], the diagonal and first
212/// superdiagonal of `A` are overwritten by `T`; elements above the first
213/// superdiagonal, together with `tau`, represent `Q`.
214/// If `fill_mode` is [`FillMode::Lower`], the diagonal and first subdiagonal
215/// of `A` are overwritten by `T`; elements below the first subdiagonal,
216/// together with `tau`, represent `Q`.
217///
218/// Provide workspace through `workspace`.
219/// Use the corresponding `*_buffer_size` helper to query the required workspace length.
220/// The workspace size in bytes is `size_of::<T>() * lwork`.
221///
222/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
223/// The problem size `n` is limited by `n * lda <= INT32_MAX` primarily due to the current implementation constraints.
224///
225/// # Errors
226///
227/// Returns an error if cuSOLVER has not been initialized, if the
228/// matrix dimensions, leading dimension, or fill mode are invalid, if the
229/// current GPU architecture is unsupported, or if cuSOLVER reports an
230/// internal failure.
231pub fn dsytrd(
232    ctx: &Context,
233    fill_mode: FillMode,
234    n: usize,
235    a: &mut DeviceMemory<f64>,
236    lda: usize,
237    d: &mut DeviceMemory<f64>,
238    e: &mut DeviceMemory<f64>,
239    tau: &mut DeviceMemory<f64>,
240    workspace: &mut DeviceMemory<f64>,
241    dev_info: &mut DeviceMemory<i32>,
242) -> Result<()> {
243    ctx.bind()?;
244    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
245    require_info_buffer(dev_info)?;
246    let lwork = dsytrd_buffer_size(ctx, fill_mode, n, a, lda, d, e, tau)?;
247    require_workspace(workspace.len(), lwork)?;
248    unsafe {
249        try_ffi!(sys::cusolverDnDsytrd(
250            ctx.as_raw(),
251            fill_mode.into(),
252            to_i32(n, "n")?,
253            a.as_mut_ptr().cast(),
254            to_i32(lda, "lda")?,
255            d.as_mut_ptr().cast(),
256            e.as_mut_ptr().cast(),
257            tau.as_mut_ptr().cast(),
258            workspace.as_mut_ptr().cast(),
259            to_i32(lwork, "lwork")?,
260            dev_info.as_mut_ptr().cast(),
261        ))?;
262    }
263    Ok(())
264}
265
266pub fn chetrd(
267    ctx: &Context,
268    fill_mode: FillMode,
269    n: usize,
270    a: &mut DeviceMemory<Complex32>,
271    lda: usize,
272    d: &mut DeviceMemory<f32>,
273    e: &mut DeviceMemory<f32>,
274    tau: &mut DeviceMemory<Complex32>,
275    workspace: &mut DeviceMemory<Complex32>,
276    dev_info: &mut DeviceMemory<i32>,
277) -> Result<()> {
278    ctx.bind()?;
279    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
280    require_info_buffer(dev_info)?;
281    let lwork = chetrd_buffer_size(ctx, fill_mode, n, a, lda, d, e, tau)?;
282    require_workspace(workspace.len(), lwork)?;
283    unsafe {
284        try_ffi!(sys::cusolverDnChetrd(
285            ctx.as_raw(),
286            fill_mode.into(),
287            to_i32(n, "n")?,
288            a.as_mut_ptr().cast(),
289            to_i32(lda, "lda")?,
290            d.as_mut_ptr().cast(),
291            e.as_mut_ptr().cast(),
292            tau.as_mut_ptr().cast(),
293            workspace.as_mut_ptr().cast(),
294            to_i32(lwork, "lwork")?,
295            dev_info.as_mut_ptr().cast(),
296        ))?;
297    }
298    Ok(())
299}
300
301pub fn zhetrd(
302    ctx: &Context,
303    fill_mode: FillMode,
304    n: usize,
305    a: &mut DeviceMemory<Complex64>,
306    lda: usize,
307    d: &mut DeviceMemory<f64>,
308    e: &mut DeviceMemory<f64>,
309    tau: &mut DeviceMemory<Complex64>,
310    workspace: &mut DeviceMemory<Complex64>,
311    dev_info: &mut DeviceMemory<i32>,
312) -> Result<()> {
313    ctx.bind()?;
314    validate_sytrd_inputs(n, a.len(), lda, d.len(), e.len(), tau.len())?;
315    require_info_buffer(dev_info)?;
316    let lwork = zhetrd_buffer_size(ctx, fill_mode, n, a, lda, d, e, tau)?;
317    require_workspace(workspace.len(), lwork)?;
318    unsafe {
319        try_ffi!(sys::cusolverDnZhetrd(
320            ctx.as_raw(),
321            fill_mode.into(),
322            to_i32(n, "n")?,
323            a.as_mut_ptr().cast(),
324            to_i32(lda, "lda")?,
325            d.as_mut_ptr().cast(),
326            e.as_mut_ptr().cast(),
327            tau.as_mut_ptr().cast(),
328            workspace.as_mut_ptr().cast(),
329            to_i32(lwork, "lwork")?,
330            dev_info.as_mut_ptr().cast(),
331        ))?;
332    }
333    Ok(())
334}
335
336pub fn sorgtr_buffer_size(
337    ctx: &Context,
338    fill_mode: FillMode,
339    n: usize,
340    a: &DeviceMemory<f32>,
341    lda: usize,
342    tau: &DeviceMemory<f32>,
343) -> Result<usize> {
344    ctx.bind()?;
345    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
346    let mut lwork = 0;
347    unsafe {
348        try_ffi!(sys::cusolverDnSorgtr_bufferSize(
349            ctx.as_raw(),
350            fill_mode.into(),
351            to_i32(n, "n")?,
352            a.as_ptr().cast(),
353            to_i32(lda, "lda")?,
354            tau.as_ptr().cast(),
355            &raw mut lwork,
356        ))?;
357    }
358    to_usize(lwork, "lwork")
359}
360
361pub fn dorgtr_buffer_size(
362    ctx: &Context,
363    fill_mode: FillMode,
364    n: usize,
365    a: &DeviceMemory<f64>,
366    lda: usize,
367    tau: &DeviceMemory<f64>,
368) -> Result<usize> {
369    ctx.bind()?;
370    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
371    let mut lwork = 0;
372    unsafe {
373        try_ffi!(sys::cusolverDnDorgtr_bufferSize(
374            ctx.as_raw(),
375            fill_mode.into(),
376            to_i32(n, "n")?,
377            a.as_ptr().cast(),
378            to_i32(lda, "lda")?,
379            tau.as_ptr().cast(),
380            &raw mut lwork,
381        ))?;
382    }
383    to_usize(lwork, "lwork")
384}
385
386pub fn cungtr_buffer_size(
387    ctx: &Context,
388    fill_mode: FillMode,
389    n: usize,
390    a: &DeviceMemory<Complex32>,
391    lda: usize,
392    tau: &DeviceMemory<Complex32>,
393) -> Result<usize> {
394    ctx.bind()?;
395    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
396    let mut lwork = 0;
397    unsafe {
398        try_ffi!(sys::cusolverDnCungtr_bufferSize(
399            ctx.as_raw(),
400            fill_mode.into(),
401            to_i32(n, "n")?,
402            a.as_ptr().cast(),
403            to_i32(lda, "lda")?,
404            tau.as_ptr().cast(),
405            &raw mut lwork,
406        ))?;
407    }
408    to_usize(lwork, "lwork")
409}
410
411pub fn zungtr_buffer_size(
412    ctx: &Context,
413    fill_mode: FillMode,
414    n: usize,
415    a: &DeviceMemory<Complex64>,
416    lda: usize,
417    tau: &DeviceMemory<Complex64>,
418) -> Result<usize> {
419    ctx.bind()?;
420    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
421    let mut lwork = 0;
422    unsafe {
423        try_ffi!(sys::cusolverDnZungtr_bufferSize(
424            ctx.as_raw(),
425            fill_mode.into(),
426            to_i32(n, "n")?,
427            a.as_ptr().cast(),
428            to_i32(lda, "lda")?,
429            tau.as_ptr().cast(),
430            &raw mut lwork,
431        ))?;
432    }
433    to_usize(lwork, "lwork")
434}
435
436/// Use the matching buffer-size helper to calculate the required workspace size.
437///
438/// The S and D data types are real valued single and double precision, respectively.
439///
440/// The C and Z data types are complex valued single and double precision, respectively.
441///
442/// Generates the orthogonal matrix `Q` from the elementary reflectors returned
443/// by `sytrd`.
444///
445/// Provide workspace through `workspace`.
446/// Use the corresponding `*_buffer_size` helper to query the required workspace length.
447/// The workspace size in bytes is `size_of::<T>() * lwork`.
448///
449/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
450///
451/// # Errors
452///
453/// Returns an error if cuSOLVER has not been initialized, if the
454/// matrix dimensions or leading dimension are invalid, if the current GPU
455/// architecture is unsupported, or if cuSOLVER reports an internal failure.
456pub fn sorgtr(
457    ctx: &Context,
458    fill_mode: FillMode,
459    n: usize,
460    a: &mut DeviceMemory<f32>,
461    lda: usize,
462    tau: &DeviceMemory<f32>,
463    workspace: &mut DeviceMemory<f32>,
464    dev_info: &mut DeviceMemory<i32>,
465) -> Result<()> {
466    ctx.bind()?;
467    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
468    require_info_buffer(dev_info)?;
469    let lwork = sorgtr_buffer_size(ctx, fill_mode, n, a, lda, tau)?;
470    require_workspace(workspace.len(), lwork)?;
471    unsafe {
472        try_ffi!(sys::cusolverDnSorgtr(
473            ctx.as_raw(),
474            fill_mode.into(),
475            to_i32(n, "n")?,
476            a.as_mut_ptr().cast(),
477            to_i32(lda, "lda")?,
478            tau.as_ptr().cast(),
479            workspace.as_mut_ptr().cast(),
480            to_i32(lwork, "lwork")?,
481            dev_info.as_mut_ptr().cast(),
482        ))?;
483    }
484    Ok(())
485}
486
487/// Use the matching buffer-size helper to calculate the required workspace size.
488///
489/// The S and D data types are real valued single and double precision, respectively.
490///
491/// The C and Z data types are complex valued single and double precision, respectively.
492///
493/// Generates the orthogonal matrix `Q` from the elementary reflectors returned
494/// by `sytrd`.
495///
496/// Provide workspace through `workspace`.
497/// Use the corresponding `*_buffer_size` helper to query the required workspace length.
498/// The workspace size in bytes is `size_of::<T>() * lwork`.
499///
500/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
501///
502/// # Errors
503///
504/// Returns an error if cuSOLVER has not been initialized, if the
505/// matrix dimensions or leading dimension are invalid, if the current GPU
506/// architecture is unsupported, or if cuSOLVER reports an internal failure.
507pub fn dorgtr(
508    ctx: &Context,
509    fill_mode: FillMode,
510    n: usize,
511    a: &mut DeviceMemory<f64>,
512    lda: usize,
513    tau: &DeviceMemory<f64>,
514    workspace: &mut DeviceMemory<f64>,
515    dev_info: &mut DeviceMemory<i32>,
516) -> Result<()> {
517    ctx.bind()?;
518    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
519    require_info_buffer(dev_info)?;
520    let lwork = dorgtr_buffer_size(ctx, fill_mode, n, a, lda, tau)?;
521    require_workspace(workspace.len(), lwork)?;
522    unsafe {
523        try_ffi!(sys::cusolverDnDorgtr(
524            ctx.as_raw(),
525            fill_mode.into(),
526            to_i32(n, "n")?,
527            a.as_mut_ptr().cast(),
528            to_i32(lda, "lda")?,
529            tau.as_ptr().cast(),
530            workspace.as_mut_ptr().cast(),
531            to_i32(lwork, "lwork")?,
532            dev_info.as_mut_ptr().cast(),
533        ))?;
534    }
535    Ok(())
536}
537
538pub fn cungtr(
539    ctx: &Context,
540    fill_mode: FillMode,
541    n: usize,
542    a: &mut DeviceMemory<Complex32>,
543    lda: usize,
544    tau: &DeviceMemory<Complex32>,
545    workspace: &mut DeviceMemory<Complex32>,
546    dev_info: &mut DeviceMemory<i32>,
547) -> Result<()> {
548    ctx.bind()?;
549    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
550    require_info_buffer(dev_info)?;
551    let lwork = cungtr_buffer_size(ctx, fill_mode, n, a, lda, tau)?;
552    require_workspace(workspace.len(), lwork)?;
553    unsafe {
554        try_ffi!(sys::cusolverDnCungtr(
555            ctx.as_raw(),
556            fill_mode.into(),
557            to_i32(n, "n")?,
558            a.as_mut_ptr().cast(),
559            to_i32(lda, "lda")?,
560            tau.as_ptr().cast(),
561            workspace.as_mut_ptr().cast(),
562            to_i32(lwork, "lwork")?,
563            dev_info.as_mut_ptr().cast(),
564        ))?;
565    }
566    Ok(())
567}
568
569pub fn zungtr(
570    ctx: &Context,
571    fill_mode: FillMode,
572    n: usize,
573    a: &mut DeviceMemory<Complex64>,
574    lda: usize,
575    tau: &DeviceMemory<Complex64>,
576    workspace: &mut DeviceMemory<Complex64>,
577    dev_info: &mut DeviceMemory<i32>,
578) -> Result<()> {
579    ctx.bind()?;
580    validate_orgtr_inputs(n, a.len(), lda, tau.len())?;
581    require_info_buffer(dev_info)?;
582    let lwork = zungtr_buffer_size(ctx, fill_mode, n, a, lda, tau)?;
583    require_workspace(workspace.len(), lwork)?;
584    unsafe {
585        try_ffi!(sys::cusolverDnZungtr(
586            ctx.as_raw(),
587            fill_mode.into(),
588            to_i32(n, "n")?,
589            a.as_mut_ptr().cast(),
590            to_i32(lda, "lda")?,
591            tau.as_ptr().cast(),
592            workspace.as_mut_ptr().cast(),
593            to_i32(lwork, "lwork")?,
594            dev_info.as_mut_ptr().cast(),
595        ))?;
596    }
597    Ok(())
598}
599
600pub fn sormtr_buffer_size(
601    ctx: &Context,
602    side: SideMode,
603    fill_mode: FillMode,
604    operation: Operation,
605    m: usize,
606    n: usize,
607    a: &DeviceMemory<f32>,
608    lda: usize,
609    tau: &DeviceMemory<f32>,
610    c: &DeviceMemory<f32>,
611    ldc: usize,
612) -> Result<usize> {
613    ctx.bind()?;
614    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
615    let mut lwork = 0;
616    unsafe {
617        try_ffi!(sys::cusolverDnSormtr_bufferSize(
618            ctx.as_raw(),
619            side.into(),
620            fill_mode.into(),
621            operation.into(),
622            to_i32(m, "m")?,
623            to_i32(n, "n")?,
624            a.as_ptr().cast(),
625            to_i32(lda, "lda")?,
626            tau.as_ptr().cast(),
627            c.as_ptr().cast(),
628            to_i32(ldc, "ldc")?,
629            &raw mut lwork,
630        ))?;
631    }
632    to_usize(lwork, "lwork")
633}
634
635pub fn dormtr_buffer_size(
636    ctx: &Context,
637    side: SideMode,
638    fill_mode: FillMode,
639    operation: Operation,
640    m: usize,
641    n: usize,
642    a: &DeviceMemory<f64>,
643    lda: usize,
644    tau: &DeviceMemory<f64>,
645    c: &DeviceMemory<f64>,
646    ldc: usize,
647) -> Result<usize> {
648    ctx.bind()?;
649    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
650    let mut lwork = 0;
651    unsafe {
652        try_ffi!(sys::cusolverDnDormtr_bufferSize(
653            ctx.as_raw(),
654            side.into(),
655            fill_mode.into(),
656            operation.into(),
657            to_i32(m, "m")?,
658            to_i32(n, "n")?,
659            a.as_ptr().cast(),
660            to_i32(lda, "lda")?,
661            tau.as_ptr().cast(),
662            c.as_ptr().cast(),
663            to_i32(ldc, "ldc")?,
664            &raw mut lwork,
665        ))?;
666    }
667    to_usize(lwork, "lwork")
668}
669
670pub fn cunmtr_buffer_size(
671    ctx: &Context,
672    side: SideMode,
673    fill_mode: FillMode,
674    operation: Operation,
675    m: usize,
676    n: usize,
677    a: &DeviceMemory<Complex32>,
678    lda: usize,
679    tau: &DeviceMemory<Complex32>,
680    c: &DeviceMemory<Complex32>,
681    ldc: usize,
682) -> Result<usize> {
683    ctx.bind()?;
684    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
685    let mut lwork = 0;
686    unsafe {
687        try_ffi!(sys::cusolverDnCunmtr_bufferSize(
688            ctx.as_raw(),
689            side.into(),
690            fill_mode.into(),
691            operation.into(),
692            to_i32(m, "m")?,
693            to_i32(n, "n")?,
694            a.as_ptr().cast(),
695            to_i32(lda, "lda")?,
696            tau.as_ptr().cast(),
697            c.as_ptr().cast(),
698            to_i32(ldc, "ldc")?,
699            &raw mut lwork,
700        ))?;
701    }
702    to_usize(lwork, "lwork")
703}
704
705pub fn zunmtr_buffer_size(
706    ctx: &Context,
707    side: SideMode,
708    fill_mode: FillMode,
709    operation: Operation,
710    m: usize,
711    n: usize,
712    a: &DeviceMemory<Complex64>,
713    lda: usize,
714    tau: &DeviceMemory<Complex64>,
715    c: &DeviceMemory<Complex64>,
716    ldc: usize,
717) -> Result<usize> {
718    ctx.bind()?;
719    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
720    let mut lwork = 0;
721    unsafe {
722        try_ffi!(sys::cusolverDnZunmtr_bufferSize(
723            ctx.as_raw(),
724            side.into(),
725            fill_mode.into(),
726            operation.into(),
727            to_i32(m, "m")?,
728            to_i32(n, "n")?,
729            a.as_ptr().cast(),
730            to_i32(lda, "lda")?,
731            tau.as_ptr().cast(),
732            c.as_ptr().cast(),
733            to_i32(ldc, "ldc")?,
734            &raw mut lwork,
735        ))?;
736    }
737    to_usize(lwork, "lwork")
738}
739
740/// Use the matching buffer-size helper to calculate the required workspace size.
741///
742/// The S and D data types are real valued single and double precision, respectively.
743///
744/// The C and Z data types are complex valued single and double precision, respectively.
745///
746/// Applies the orthogonal matrix `Q`, represented by the elementary reflectors
747/// returned by `sytrd`, to `C` and stores the result in `C`.
748///
749/// `side` selects whether `Q` is applied from the left or right, and
750/// `operation` selects whether `Q` is transposed.
751///
752/// Provide workspace through `workspace`.
753/// Use the corresponding `*_buffer_size` helper to query the required workspace length.
754/// The workspace size in bytes is `size_of::<T>() * lwork`.
755///
756/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
757///
758/// # Errors
759///
760/// Returns an error if cuSOLVER has not been initialized, if the
761/// matrix dimensions or leading dimensions are invalid, if the current GPU
762/// architecture is unsupported, or if cuSOLVER reports an internal failure.
763pub fn sormtr(
764    ctx: &Context,
765    side: SideMode,
766    fill_mode: FillMode,
767    operation: Operation,
768    m: usize,
769    n: usize,
770    a: &mut DeviceMemory<f32>,
771    lda: usize,
772    tau: &mut DeviceMemory<f32>,
773    c: &mut DeviceMemory<f32>,
774    ldc: usize,
775    workspace: &mut DeviceMemory<f32>,
776    dev_info: &mut DeviceMemory<i32>,
777) -> Result<()> {
778    ctx.bind()?;
779    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
780    require_info_buffer(dev_info)?;
781    let lwork = sormtr_buffer_size(ctx, side, fill_mode, operation, m, n, a, lda, tau, c, ldc)?;
782    require_workspace(workspace.len(), lwork)?;
783    unsafe {
784        try_ffi!(sys::cusolverDnSormtr(
785            ctx.as_raw(),
786            side.into(),
787            fill_mode.into(),
788            operation.into(),
789            to_i32(m, "m")?,
790            to_i32(n, "n")?,
791            a.as_mut_ptr().cast(),
792            to_i32(lda, "lda")?,
793            tau.as_mut_ptr().cast(),
794            c.as_mut_ptr().cast(),
795            to_i32(ldc, "ldc")?,
796            workspace.as_mut_ptr().cast(),
797            to_i32(lwork, "lwork")?,
798            dev_info.as_mut_ptr().cast(),
799        ))?;
800    }
801    Ok(())
802}
803
804/// Use the matching buffer-size helper to calculate the required workspace size.
805///
806/// The S and D data types are real valued single and double precision, respectively.
807///
808/// The C and Z data types are complex valued single and double precision, respectively.
809///
810/// Applies the orthogonal matrix `Q`, represented by the elementary reflectors
811/// returned by `sytrd`, to `C` and stores the result in `C`.
812///
813/// `side` selects whether `Q` is applied from the left or right, and
814/// `operation` selects whether `Q` is transposed.
815///
816/// Provide workspace through `workspace`.
817/// Use the corresponding `*_buffer_size` helper to query the required workspace length.
818/// The workspace size in bytes is `size_of::<T>() * lwork`.
819///
820/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
821///
822/// # Errors
823///
824/// Returns an error if cuSOLVER has not been initialized, if the
825/// matrix dimensions or leading dimensions are invalid, if the current GPU
826/// architecture is unsupported, or if cuSOLVER reports an internal failure.
827pub fn dormtr(
828    ctx: &Context,
829    side: SideMode,
830    fill_mode: FillMode,
831    operation: Operation,
832    m: usize,
833    n: usize,
834    a: &mut DeviceMemory<f64>,
835    lda: usize,
836    tau: &mut DeviceMemory<f64>,
837    c: &mut DeviceMemory<f64>,
838    ldc: usize,
839    workspace: &mut DeviceMemory<f64>,
840    dev_info: &mut DeviceMemory<i32>,
841) -> Result<()> {
842    ctx.bind()?;
843    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
844    require_info_buffer(dev_info)?;
845    let lwork = dormtr_buffer_size(ctx, side, fill_mode, operation, m, n, a, lda, tau, c, ldc)?;
846    require_workspace(workspace.len(), lwork)?;
847    unsafe {
848        try_ffi!(sys::cusolverDnDormtr(
849            ctx.as_raw(),
850            side.into(),
851            fill_mode.into(),
852            operation.into(),
853            to_i32(m, "m")?,
854            to_i32(n, "n")?,
855            a.as_mut_ptr().cast(),
856            to_i32(lda, "lda")?,
857            tau.as_mut_ptr().cast(),
858            c.as_mut_ptr().cast(),
859            to_i32(ldc, "ldc")?,
860            workspace.as_mut_ptr().cast(),
861            to_i32(lwork, "lwork")?,
862            dev_info.as_mut_ptr().cast(),
863        ))?;
864    }
865    Ok(())
866}
867
868pub fn cunmtr(
869    ctx: &Context,
870    side: SideMode,
871    fill_mode: FillMode,
872    operation: Operation,
873    m: usize,
874    n: usize,
875    a: &mut DeviceMemory<Complex32>,
876    lda: usize,
877    tau: &mut DeviceMemory<Complex32>,
878    c: &mut DeviceMemory<Complex32>,
879    ldc: usize,
880    workspace: &mut DeviceMemory<Complex32>,
881    dev_info: &mut DeviceMemory<i32>,
882) -> Result<()> {
883    ctx.bind()?;
884    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
885    require_info_buffer(dev_info)?;
886    let lwork = cunmtr_buffer_size(ctx, side, fill_mode, operation, m, n, a, lda, tau, c, ldc)?;
887    require_workspace(workspace.len(), lwork)?;
888    unsafe {
889        try_ffi!(sys::cusolverDnCunmtr(
890            ctx.as_raw(),
891            side.into(),
892            fill_mode.into(),
893            operation.into(),
894            to_i32(m, "m")?,
895            to_i32(n, "n")?,
896            a.as_mut_ptr().cast(),
897            to_i32(lda, "lda")?,
898            tau.as_mut_ptr().cast(),
899            c.as_mut_ptr().cast(),
900            to_i32(ldc, "ldc")?,
901            workspace.as_mut_ptr().cast(),
902            to_i32(lwork, "lwork")?,
903            dev_info.as_mut_ptr().cast(),
904        ))?;
905    }
906    Ok(())
907}
908
909pub fn zunmtr(
910    ctx: &Context,
911    side: SideMode,
912    fill_mode: FillMode,
913    operation: Operation,
914    m: usize,
915    n: usize,
916    a: &mut DeviceMemory<Complex64>,
917    lda: usize,
918    tau: &mut DeviceMemory<Complex64>,
919    c: &mut DeviceMemory<Complex64>,
920    ldc: usize,
921    workspace: &mut DeviceMemory<Complex64>,
922    dev_info: &mut DeviceMemory<i32>,
923) -> Result<()> {
924    ctx.bind()?;
925    validate_ormtr_inputs(side, m, n, a.len(), lda, tau.len(), c.len(), ldc)?;
926    require_info_buffer(dev_info)?;
927    let lwork = zunmtr_buffer_size(ctx, side, fill_mode, operation, m, n, a, lda, tau, c, ldc)?;
928    require_workspace(workspace.len(), lwork)?;
929    unsafe {
930        try_ffi!(sys::cusolverDnZunmtr(
931            ctx.as_raw(),
932            side.into(),
933            fill_mode.into(),
934            operation.into(),
935            to_i32(m, "m")?,
936            to_i32(n, "n")?,
937            a.as_mut_ptr().cast(),
938            to_i32(lda, "lda")?,
939            tau.as_mut_ptr().cast(),
940            c.as_mut_ptr().cast(),
941            to_i32(ldc, "ldc")?,
942            workspace.as_mut_ptr().cast(),
943            to_i32(lwork, "lwork")?,
944            dev_info.as_mut_ptr().cast(),
945        ))?;
946    }
947    Ok(())
948}