Skip to main content

singe_cusolver/dense/
generic.rs

1use singe_cuda::{
2    data_type::{DataType, DataTypeLike},
3    memory::DeviceMemory,
4};
5
6use crate::{
7    context::Context,
8    dense::validation::{
9        require_host_workspace, require_info_buffer, require_pivot64_buffer,
10        require_workspace_bytes, validate_x_matrix, validate_xlarft_inputs,
11    },
12    error::Result,
13    layout::{ByteWorkspaceMut, MatrixMut, MatrixRef, VectorRef, WorkspaceSizes},
14    params::Params,
15    sys, try_ffi,
16    types::{DiagonalType, DirectMode, FillMode, Operation, StorevMode},
17    utility::{to_i64, to_usize},
18};
19
20pub fn xpotrf_buffer_size<TA: DataTypeLike>(
21    ctx: &Context,
22    params: &Params,
23    fill_mode: FillMode,
24    n: usize,
25    a: MatrixRef<'_, TA>,
26    compute_type: DataType,
27) -> Result<WorkspaceSizes> {
28    ctx.bind()?;
29    let a_type = TA::data_type();
30    validate_x_matrix(n, n, a.data.byte_len(), a.leading_dimension, a_type)?;
31    let mut device_bytes = 0;
32    let mut host_bytes = 0;
33    unsafe {
34        try_ffi!(sys::cusolverDnXpotrf_bufferSize(
35            ctx.as_raw(),
36            params.as_raw(),
37            fill_mode.into(),
38            to_i64(n, "n")?,
39            a_type.into(),
40            a.data.as_ptr().cast(),
41            to_i64(a.leading_dimension, "lda")?,
42            compute_type.into(),
43            &raw mut device_bytes,
44            &raw mut host_bytes,
45        ))?;
46    }
47    Ok(WorkspaceSizes::new(
48        to_usize(device_bytes, "device workspace size")?,
49        to_usize(host_bytes, "host workspace size")?,
50    ))
51}
52
53/// Use [`xpotrf_buffer_size`] to calculate the sizes needed for pre-allocated
54/// workspace.
55///
56/// Computes the Cholesky factorization of a Hermitian positive-definite matrix.
57///
58/// `A` is an $n \times n$ Hermitian matrix; only its lower or upper triangular
59/// part is meaningful.
60/// `fill_mode` indicates which part of the matrix is used.
61/// The operation leaves the other part untouched.
62///
63/// If `fill_mode` is [`FillMode::Lower`], only the lower triangular part of `A` is processed and replaced by the lower triangular Cholesky factor `L`.
64///
65/// If `fill_mode` is [`FillMode::Upper`], only the upper triangular part of `A` is processed and replaced by the upper triangular Cholesky factor `U`.
66///
67/// Provide device and host workspace through `workspace`.
68/// Use [`xpotrf_buffer_size`] to determine the required sizes for
69/// `workspace.device` and `workspace.host`.
70///
71/// If Cholesky factorization fails, some leading minor of `A` is not positive
72/// definite, or equivalently some diagonal element of `L` or `U` is not a real
73/// number.
74/// `dev_info` reports the smallest leading minor of `A` that is not positive definite.
75///
76/// If the reported `info` value is `-i`, the `i`th parameter is invalid.
77///
78/// Currently, [`xpotrf`] supports only the default algorithm.
79///
80/// **Algorithms supported by [`xpotrf`]**
81///
82/// | Algorithm | Notes |
83/// | --- | --- |
84/// | [`AlgorithmMode::Default`](crate::types::AlgorithmMode::Default) | Default algorithm. |
85///
86/// List of input arguments for [`xpotrf_buffer_size`] and [`xpotrf`]:
87///
88/// The generic cuSOLVER routine separates matrix and compute data types: `data_type_a` is
89/// the data type of matrix `A`, and `compute_type` is the operation's compute
90/// type.
91/// [`xpotrf`] only supports the following four combinations.
92///
93/// **Valid combination of data type and compute type**
94///
95/// | **data_type_a** | **compute_type** | **Meaning** |
96/// | --- | --- | --- |
97/// | [`DataType::F32`] | [`DataType::F32`] | `SPOTRF` |
98/// | [`DataType::F64`] | [`DataType::F64`] | `DPOTRF` |
99/// | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | `CPOTRF` |
100/// | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | `ZPOTRF` |
101///
102/// # Errors
103///
104/// Returns an error if cuSOLVER has not been initialized, if the
105/// matrix dimensions or leading dimension are invalid, or if cuSOLVER reports
106/// an internal failure.
107pub fn xpotrf<TA: DataTypeLike>(
108    ctx: &Context,
109    params: &Params,
110    fill_mode: FillMode,
111    n: usize,
112    a: MatrixMut<'_, TA>,
113    compute_type: DataType,
114    workspace: ByteWorkspaceMut<'_>,
115    dev_info: &mut DeviceMemory<i32>,
116) -> Result<()> {
117    ctx.bind()?;
118    let a_type = TA::data_type();
119    validate_x_matrix(n, n, a.data.byte_len(), a.leading_dimension, a_type)?;
120    require_info_buffer(dev_info)?;
121    let workspace_sizes = xpotrf_buffer_size(ctx, params, fill_mode, n, a.as_ref(), compute_type)?;
122    require_workspace_bytes(workspace.device.byte_len(), workspace_sizes.device_bytes)?;
123    require_host_workspace(workspace.host.len(), workspace_sizes.host_bytes)?;
124    unsafe {
125        try_ffi!(sys::cusolverDnXpotrf(
126            ctx.as_raw(),
127            params.as_raw(),
128            fill_mode.into(),
129            to_i64(n, "n")?,
130            a_type.into(),
131            a.data.as_mut_ptr().cast(),
132            to_i64(a.leading_dimension, "lda")?,
133            compute_type.into(),
134            workspace.device.as_mut_ptr().cast(),
135            workspace_sizes.device_bytes as _,
136            workspace.host.as_mut_ptr().cast(),
137            workspace_sizes.host_bytes as _,
138            dev_info.as_mut_ptr().cast(),
139        ))?;
140    }
141    Ok(())
142}
143
144/// Solves a system of linear equations.
145///
146/// Here `A` is an $n \times n$ Hermitian matrix; only its lower or upper
147/// triangular part is meaningful.
148/// `fill_mode` indicates which part of the matrix is used.
149/// The operation leaves the other part untouched.
150///
151/// Call [`xpotrf`] first to factorize matrix `A`.
152/// If `fill_mode` is [`FillMode::Lower`], `A` is lower triangular Cholesky factor `L` corresponding to $A = L\cdot L^{H}$.
153/// If `fill_mode` is [`FillMode::Upper`], `A` is upper triangular Cholesky factor `U` corresponding to $A = U^{H}\cdot U$.
154///
155/// The operation is in-place, that is, matrix `X` overwrites matrix `B` with the same leading dimension `ldb`.
156///
157/// If the reported `info` value is `-i`, the `i`th parameter is invalid.
158///
159/// Currently, [`xpotrs`] supports only the default algorithm.
160///
161/// **Algorithms supported by [`xpotrs`]**
162///
163/// | Algorithm | Notes |
164/// | --- | --- |
165/// | [`AlgorithmMode::Default`](crate::types::AlgorithmMode::Default) | Default algorithm. |
166///
167/// List of input arguments for [`xpotrs`]:
168///
169/// The generic cuSOLVER routine separates matrix data types: `data_type_a` is the data type
170/// of matrix `A`, and `data_type_b` is the data type of matrix `B`.
171/// [`xpotrs`] only supports the following four combinations.
172///
173/// **Valid combination of data type and compute type**
174///
175/// | **data_type_a** | **data_type_b** | **Meaning** |
176/// | --- | --- | --- |
177/// | [`DataType::F32`] | [`DataType::F32`] | `SPOTRS` |
178/// | [`DataType::F64`] | [`DataType::F64`] | `DPOTRS` |
179/// | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | `CPOTRS` |
180/// | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | `ZPOTRS` |
181///
182/// # Errors
183///
184/// Returns an error if cuSOLVER has not been initialized, if the
185/// matrix dimensions, right-hand-side count, or leading dimensions are
186/// invalid, or if cuSOLVER reports an internal failure.
187pub fn xpotrs<TA: DataTypeLike, TB: DataTypeLike>(
188    ctx: &Context,
189    params: &Params,
190    fill_mode: FillMode,
191    n: usize,
192    nrhs: usize,
193    a: MatrixRef<'_, TA>,
194    b: MatrixMut<'_, TB>,
195    dev_info: &mut DeviceMemory<i32>,
196) -> Result<()> {
197    ctx.bind()?;
198    let a_type = TA::data_type();
199    let b_type = TB::data_type();
200    validate_x_matrix(n, n, a.data.byte_len(), a.leading_dimension, a_type)?;
201    validate_x_matrix(n, nrhs, b.data.byte_len(), b.leading_dimension, b_type)?;
202    require_info_buffer(dev_info)?;
203    unsafe {
204        try_ffi!(sys::cusolverDnXpotrs(
205            ctx.as_raw(),
206            params.as_raw(),
207            fill_mode.into(),
208            to_i64(n, "n")?,
209            to_i64(nrhs, "nrhs")?,
210            a_type.into(),
211            a.data.as_ptr().cast(),
212            to_i64(a.leading_dimension, "lda")?,
213            b_type.into(),
214            b.data.as_mut_ptr().cast(),
215            to_i64(b.leading_dimension, "ldb")?,
216            dev_info.as_mut_ptr().cast(),
217        ))?;
218    }
219    Ok(())
220}
221
222pub fn xtrtri_buffer_size<TA: DataTypeLike>(
223    ctx: &Context,
224    fill_mode: FillMode,
225    diagonal_type: DiagonalType,
226    n: usize,
227    a: MatrixRef<'_, TA>,
228) -> Result<WorkspaceSizes> {
229    ctx.bind()?;
230    validate_x_matrix(
231        n,
232        n,
233        a.data.byte_len(),
234        a.leading_dimension,
235        TA::data_type(),
236    )?;
237    let mut device_bytes = 0;
238    let mut host_bytes = 0;
239    unsafe {
240        try_ffi!(sys::cusolverDnXtrtri_bufferSize(
241            ctx.as_raw(),
242            fill_mode.into(),
243            diagonal_type.into(),
244            to_i64(n, "n")?,
245            TA::data_type().into(),
246            a.data.as_ptr().cast_mut().cast(),
247            to_i64(a.leading_dimension, "lda")?,
248            &raw mut device_bytes,
249            &raw mut host_bytes,
250        ))?;
251    }
252    Ok(WorkspaceSizes::new(
253        to_usize(device_bytes, "device workspace size")?,
254        to_usize(host_bytes, "host workspace size")?,
255    ))
256}
257
258/// Use the matching buffer-size helper to calculate the sizes needed for pre-allocated workspace.
259///
260/// Computes the inverse of a triangular matrix through the generic cuSOLVER routine.
261///
262/// `A` is an $n \times n$ triangular matrix, only lower or upper part is meaningful.
263/// `fill_mode` indicates which part of the matrix is used.
264/// The other triangular part is left unchanged.
265///
266/// If `fill_mode` is [`FillMode::Lower`], only the lower triangular part of `A` is processed and replaced by the lower triangular inverse.
267///
268/// If `fill_mode` is [`FillMode::Upper`], only the upper triangular part of `A` is processed and replaced by the upper triangular inverse.
269///
270/// Provide device and host workspace through `workspace`.
271/// Use [`xtrtri_buffer_size`] to determine the required sizes for
272/// `workspace.device` and `workspace.host`.
273///
274/// If matrix inversion fails, `dev_info = i` shows `A(i, i) = 0`.
275///
276/// If the reported `info` value is `-i`, the `i`th parameter is invalid.
277///
278/// List of input arguments for [`xtrtri_buffer_size`] and [`xtrtri`]:
279///
280/// **Valid data types**
281///
282/// | Algorithm | Notes |
283/// | --- | --- |
284/// | data type | Meaning |
285/// | [`DataType::F32`] | `STRTRI` |
286/// | [`DataType::F64`] | `DTRTRI` |
287/// | [`DataType::ComplexF32`] | `CTRTRI` |
288/// | [`DataType::ComplexF64`] | `ZTRTRI` |
289///
290/// # Errors
291///
292/// Returns an error if cuSOLVER has not been initialized, if the
293/// matrix dimensions or leading dimension are invalid, if the data type is not
294/// supported, or if cuSOLVER reports an internal failure.
295pub fn xtrtri<TA: DataTypeLike>(
296    ctx: &Context,
297    fill_mode: FillMode,
298    diagonal_type: DiagonalType,
299    n: usize,
300    a: MatrixMut<'_, TA>,
301    workspace: ByteWorkspaceMut<'_>,
302    dev_info: &mut DeviceMemory<i32>,
303) -> Result<()> {
304    ctx.bind()?;
305    validate_x_matrix(
306        n,
307        n,
308        a.data.byte_len(),
309        a.leading_dimension,
310        TA::data_type(),
311    )?;
312    require_info_buffer(dev_info)?;
313    let workspace_sizes = xtrtri_buffer_size(ctx, fill_mode, diagonal_type, n, a.as_ref())?;
314    require_workspace_bytes(workspace.device.byte_len(), workspace_sizes.device_bytes)?;
315    require_host_workspace(workspace.host.len(), workspace_sizes.host_bytes)?;
316    unsafe {
317        try_ffi!(sys::cusolverDnXtrtri(
318            ctx.as_raw(),
319            fill_mode.into(),
320            diagonal_type.into(),
321            to_i64(n, "n")?,
322            TA::data_type().into(),
323            a.data.as_mut_ptr().cast(),
324            to_i64(a.leading_dimension, "lda")?,
325            workspace.device.as_mut_ptr().cast(),
326            workspace_sizes.device_bytes as _,
327            workspace.host.as_mut_ptr().cast(),
328            workspace_sizes.host_bytes as _,
329            dev_info.as_mut_ptr().cast(),
330        ))?;
331    }
332    Ok(())
333}
334
335pub fn xgetrf_buffer_size<TA: DataTypeLike>(
336    ctx: &Context,
337    params: &Params,
338    m: usize,
339    n: usize,
340    a: MatrixRef<'_, TA>,
341    compute_type: DataType,
342) -> Result<WorkspaceSizes> {
343    ctx.bind()?;
344    let a_type = TA::data_type();
345    validate_x_matrix(m, n, a.data.byte_len(), a.leading_dimension, a_type)?;
346    let mut device_bytes = 0;
347    let mut host_bytes = 0;
348    unsafe {
349        try_ffi!(sys::cusolverDnXgetrf_bufferSize(
350            ctx.as_raw(),
351            params.as_raw(),
352            to_i64(m, "m")?,
353            to_i64(n, "n")?,
354            a_type.into(),
355            a.data.as_ptr().cast(),
356            to_i64(a.leading_dimension, "lda")?,
357            compute_type.into(),
358            &raw mut device_bytes,
359            &raw mut host_bytes,
360        ))?;
361    }
362    Ok(WorkspaceSizes::new(
363        to_usize(device_bytes, "device workspace size")?,
364        to_usize(host_bytes, "host workspace size")?,
365    ))
366}
367
368/// Computes the LU factorization of an $m \times n$ matrix
369///
370/// where `A` is an $m \times n$ matrix, `P` is a permutation matrix, `L` is a lower triangular matrix with unit diagonal, and `U` is an upper triangular matrix.
371///
372/// If LU factorization failed, that is, matrix `A` (`U`) is singular, `dev_info = i` indicates `U(i,i) = 0`.
373///
374/// If the reported `info` value is `-i`, the `i`th parameter is invalid.
375///
376/// If `pivots` is `None`, no pivoting is performed.
377/// The factorization is `A=L*U`, which is not numerically stable.
378///
379/// Whether LU factorization succeeds or fails, `pivots` contains the pivoting
380/// sequence. Row `i` is interchanged with row `pivots[i]`.
381///
382/// Provide device and host workspace through `workspace`.
383/// Use [`xgetrf_buffer_size`] to determine the required sizes for
384/// `workspace.device` and `workspace.host`.
385///
386/// Callers can combine [`xgetrf`] and [`xgetrs`] to complete a linear solver.
387///
388/// Currently, [`xgetrf`] supports two algorithms.
389/// To select the legacy implementation, call [`Params::set_adv_options`].
390///
391/// **Algorithms supported by [`xgetrf`]**
392///
393/// | Algorithm | Notes |
394/// | --- | --- |
395/// | [`AlgorithmMode::Default`](crate::types::AlgorithmMode::Default) | Fastest algorithm; requires a large workspace of `m*n` elements. |
396/// | [`AlgorithmMode::Algorithm1`](crate::types::AlgorithmMode::Algorithm1) | Legacy implementation. |
397///
398/// List of input arguments for [`xgetrf_buffer_size`] and [`xgetrf`]:
399///
400/// The generic cuSOLVER routine has two data types: `data_type_a` is the data type of matrix `A`, and `compute_type` is the operation's compute type.
401/// [`xgetrf`] only supports the following four combinations.
402///
403/// **Valid combination of data type and compute type**
404///
405/// | **data_type_a** | **compute_type** | **Meaning** |
406/// | --- | --- | --- |
407/// | [`DataType::F32`] | [`DataType::F32`] | `SGETRF` |
408/// | [`DataType::F64`] | [`DataType::F64`] | `DGETRF` |
409/// | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | `CGETRF` |
410/// | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | `ZGETRF` |
411///
412/// # Errors
413///
414/// Returns an error if cuSOLVER has not been initialized, if the
415/// matrix dimensions or leading dimension are invalid, or if cuSOLVER reports
416/// an internal failure.
417pub fn xgetrf<TA: DataTypeLike>(
418    ctx: &Context,
419    params: &Params,
420    m: usize,
421    n: usize,
422    a: MatrixMut<'_, TA>,
423    pivots: Option<&mut DeviceMemory<i64>>,
424    compute_type: DataType,
425    workspace: ByteWorkspaceMut<'_>,
426    dev_info: &mut DeviceMemory<i32>,
427) -> Result<()> {
428    ctx.bind()?;
429    let a_type = TA::data_type();
430    validate_x_matrix(m, n, a.data.byte_len(), a.leading_dimension, a_type)?;
431    if let Some(pivots) = pivots.as_ref() {
432        require_pivot64_buffer(pivots, m.min(n))?;
433    }
434    require_info_buffer(dev_info)?;
435    let workspace_sizes = xgetrf_buffer_size(ctx, params, m, n, a.as_ref(), compute_type)?;
436    require_workspace_bytes(workspace.device.byte_len(), workspace_sizes.device_bytes)?;
437    require_host_workspace(workspace.host.len(), workspace_sizes.host_bytes)?;
438    unsafe {
439        try_ffi!(sys::cusolverDnXgetrf(
440            ctx.as_raw(),
441            params.as_raw(),
442            to_i64(m, "m")?,
443            to_i64(n, "n")?,
444            a_type.into(),
445            a.data.as_mut_ptr().cast(),
446            to_i64(a.leading_dimension, "lda")?,
447            pivots.map_or(std::ptr::null_mut(), |p| p.as_mut_ptr()),
448            compute_type.into(),
449            workspace.device.as_mut_ptr().cast(),
450            workspace_sizes.device_bytes as _,
451            workspace.host.as_mut_ptr().cast(),
452            workspace_sizes.host_bytes as _,
453            dev_info.as_mut_ptr().cast(),
454        ))?;
455    }
456    Ok(())
457}
458
459/// Solves a linear system of multiple right-hand sides
460///
461/// where `A` is an $n \times n$ matrix, and was LU-factored by [`xgetrf`], that is, lower triangular part of A is `L`, and upper triangular part (including diagonal elements) of `A` is `U`.
462/// `B` is an $n \times {nrhs}$ right-hand side matrix.
463///
464/// The `operation` argument is described by [`Operation`].
465///
466/// `pivots` is an output of [`xgetrf`].
467/// It contains the pivot indices used to permute the right-hand sides.
468///
469/// If the reported `info` value is `-i`, the `i`th parameter is invalid.
470///
471/// Callers can combine [`xgetrf`] and [`xgetrs`] to complete a linear solver.
472///
473/// Currently, [`xgetrs`] supports only the default algorithm.
474///
475/// **Algorithms supported by [`xgetrs`]**
476///
477/// | Algorithm | Notes |
478/// | --- | --- |
479/// | [`AlgorithmMode::Default`](crate::types::AlgorithmMode::Default) | Default algorithm. |
480///
481/// List of input arguments for [`xgetrs`]:
482///
483/// The generic cuSOLVER routine has two data types: `data_type_a` is the data type of matrix `A`, and `data_type_b` is the data type of matrix `B`.
484/// [`xgetrs`] only supports the following four combinations:
485///
486/// **Valid combination of data type and compute type**
487///
488/// | **data_type_a** | **data_type_b** | **Meaning** |
489/// | --- | --- | --- |
490/// | [`DataType::F32`] | [`DataType::F32`] | `SGETRS` |
491/// | [`DataType::F64`] | [`DataType::F64`] | `DGETRS` |
492/// | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | `CGETRS` |
493/// | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | `ZGETRS` |
494///
495/// # Errors
496///
497/// Returns an error if cuSOLVER has not been initialized, if the
498/// matrix dimensions or leading dimensions are invalid, or if cuSOLVER reports
499/// an internal failure.
500pub fn xgetrs<TA: DataTypeLike, TB: DataTypeLike>(
501    ctx: &Context,
502    params: &Params,
503    operation: Operation,
504    n: usize,
505    nrhs: usize,
506    a: MatrixRef<'_, TA>,
507    pivots: &DeviceMemory<i64>,
508    b: MatrixMut<'_, TB>,
509    dev_info: &mut DeviceMemory<i32>,
510) -> Result<()> {
511    ctx.bind()?;
512    let a_type = TA::data_type();
513    let b_type = TB::data_type();
514    validate_x_matrix(n, n, a.data.byte_len(), a.leading_dimension, a_type)?;
515    require_pivot64_buffer(pivots, n)?;
516    validate_x_matrix(n, nrhs, b.data.byte_len(), b.leading_dimension, b_type)?;
517    require_info_buffer(dev_info)?;
518    unsafe {
519        try_ffi!(sys::cusolverDnXgetrs(
520            ctx.as_raw(),
521            params.as_raw(),
522            operation.into(),
523            to_i64(n, "n")?,
524            to_i64(nrhs, "nrhs")?,
525            a_type.into(),
526            a.data.as_ptr().cast(),
527            to_i64(a.leading_dimension, "lda")?,
528            pivots.as_ptr().cast(),
529            b_type.into(),
530            b.data.as_mut_ptr().cast(),
531            to_i64(b.leading_dimension, "ldb")?,
532            dev_info.as_mut_ptr().cast(),
533        ))?;
534    }
535    Ok(())
536}
537
538pub fn xsytrs_buffer_size<TA: DataTypeLike, TB: DataTypeLike>(
539    ctx: &Context,
540    fill_mode: FillMode,
541    n: usize,
542    nrhs: usize,
543    a: MatrixRef<'_, TA>,
544    pivots: Option<&DeviceMemory<i64>>,
545    b: MatrixRef<'_, TB>,
546) -> Result<WorkspaceSizes> {
547    ctx.bind()?;
548    validate_x_matrix(
549        n,
550        n,
551        a.data.byte_len(),
552        a.leading_dimension,
553        TA::data_type(),
554    )?;
555    validate_x_matrix(
556        n,
557        nrhs,
558        b.data.byte_len(),
559        b.leading_dimension,
560        TB::data_type(),
561    )?;
562    if let Some(pivots) = pivots {
563        require_pivot64_buffer(pivots, n)?;
564    }
565
566    let mut device_bytes = 0;
567    let mut host_bytes = 0;
568    unsafe {
569        try_ffi!(sys::cusolverDnXsytrs_bufferSize(
570            ctx.as_raw(),
571            fill_mode.into(),
572            to_i64(n, "n")?,
573            to_i64(nrhs, "nrhs")?,
574            TA::data_type().into(),
575            a.data.as_ptr().cast(),
576            to_i64(a.leading_dimension, "lda")?,
577            pivots.map_or(std::ptr::null(), DeviceMemory::as_ptr),
578            TB::data_type().into(),
579            b.data.as_ptr().cast_mut().cast(),
580            to_i64(b.leading_dimension, "ldb")?,
581            &raw mut device_bytes,
582            &raw mut host_bytes,
583        ))?;
584    }
585    Ok(WorkspaceSizes::new(
586        to_usize(device_bytes, "device workspace size")?,
587        to_usize(host_bytes, "host workspace size")?,
588    ))
589}
590
591/// Use the matching buffer-size helper to calculate the sizes needed for pre-allocated workspace.
592///
593/// Solves a system of linear equations through the generic cuSOLVER routine.
594///
595/// `A` contains the factorization produced by the typed `*sytrf` operations in this module.
596/// Only the lower or upper part is meaningful; the other part is left untouched.
597///
598/// Provide the pivot indices returned by the matching `*sytrf` operation, along
599/// with device and host workspace through `workspace`.
600/// Use [`xsytrs_buffer_size`] to determine the required sizes for
601/// `workspace.device` and `workspace.host`.
602/// To factorize and solve the symmetric system without pivoting, pass `None`
603/// for the pivot buffer to both the matching `*sytrf` operation and [`xsytrs`].
604///
605/// If the reported `dev_info` value is `-i`, the `i`th parameter is invalid.
606///
607/// List of input arguments for [`xsytrs_buffer_size`] and [`xsytrs`]:
608///
609/// The generic cuSOLVER routine has two data types: `data_type_a` is the data type of the
610/// matrix `A`, and `data_type_b` is the data type of the matrix `B`.
611/// [`xsytrs`] only supports the following four combinations:
612///
613/// **Valid combination of data type and compute type**
614///
615/// | **data_type_a** | **data_type_b** | **Meaning** |
616/// | --- | --- | --- |
617/// | [`DataType::F32`] | [`DataType::F32`] | `SSYTRS` |
618/// | [`DataType::F64`] | [`DataType::F64`] | `DSYTRS` |
619/// | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | `CSYTRS` |
620/// | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | `ZSYTRS` |
621///
622/// # Errors
623///
624/// Returns an error if cuSOLVER has not been initialized, if the
625/// matrix dimensions or leading dimension are invalid, if the matrix data type
626/// is not supported, or if cuSOLVER reports an internal failure.
627pub fn xsytrs<TA: DataTypeLike, TB: DataTypeLike>(
628    ctx: &Context,
629    fill_mode: FillMode,
630    n: usize,
631    nrhs: usize,
632    a: MatrixRef<'_, TA>,
633    pivots: Option<&DeviceMemory<i64>>,
634    b: MatrixMut<'_, TB>,
635    workspace: ByteWorkspaceMut<'_>,
636    dev_info: &mut DeviceMemory<i32>,
637) -> Result<()> {
638    ctx.bind()?;
639    validate_x_matrix(
640        n,
641        n,
642        a.data.byte_len(),
643        a.leading_dimension,
644        TA::data_type(),
645    )?;
646    validate_x_matrix(
647        n,
648        nrhs,
649        b.data.byte_len(),
650        b.leading_dimension,
651        TB::data_type(),
652    )?;
653    if let Some(pivots) = pivots {
654        require_pivot64_buffer(pivots, n)?;
655    }
656    require_info_buffer(dev_info)?;
657    let workspace_sizes = xsytrs_buffer_size(ctx, fill_mode, n, nrhs, a, pivots, b.as_ref())?;
658    require_workspace_bytes(workspace.device.byte_len(), workspace_sizes.device_bytes)?;
659    require_host_workspace(workspace.host.len(), workspace_sizes.host_bytes)?;
660    unsafe {
661        try_ffi!(sys::cusolverDnXsytrs(
662            ctx.as_raw(),
663            fill_mode.into(),
664            to_i64(n, "n")?,
665            to_i64(nrhs, "nrhs")?,
666            TA::data_type().into(),
667            a.data.as_ptr().cast(),
668            to_i64(a.leading_dimension, "lda")?,
669            pivots.map_or(std::ptr::null(), DeviceMemory::as_ptr),
670            TB::data_type().into(),
671            b.data.as_mut_ptr().cast(),
672            to_i64(b.leading_dimension, "ldb")?,
673            workspace.device.as_mut_ptr().cast(),
674            workspace_sizes.device_bytes as _,
675            workspace.host.as_mut_ptr().cast(),
676            workspace_sizes.host_bytes as _,
677            dev_info.as_mut_ptr().cast(),
678        ))?;
679    }
680    Ok(())
681}
682
683pub fn xlarft_buffer_size<TV: DataTypeLike, TTau: DataTypeLike, TT: DataTypeLike>(
684    ctx: &Context,
685    params: &Params,
686    direct: DirectMode,
687    storev: StorevMode,
688    n: usize,
689    k: usize,
690    v: MatrixRef<'_, TV>,
691    tau: VectorRef<'_, TTau>,
692    t: MatrixRef<'_, TT>,
693    compute_type: DataType,
694) -> Result<WorkspaceSizes> {
695    ctx.bind()?;
696    let v_type = TV::data_type();
697    let tau_type = TTau::data_type();
698    let t_type = TT::data_type();
699    validate_xlarft_inputs(
700        n,
701        k,
702        storev,
703        v.data.byte_len(),
704        v.leading_dimension,
705        v_type,
706        tau.data.byte_len(),
707        tau_type,
708        t.data.byte_len(),
709        t.leading_dimension,
710        t_type,
711    )?;
712    let mut device_bytes = 0;
713    let mut host_bytes = 0;
714    unsafe {
715        try_ffi!(sys::cusolverDnXlarft_bufferSize(
716            ctx.as_raw(),
717            params.as_raw(),
718            direct.into(),
719            storev.into(),
720            to_i64(n, "n")?,
721            to_i64(k, "k")?,
722            v_type.into(),
723            v.data.as_ptr().cast(),
724            to_i64(v.leading_dimension, "ldv")?,
725            tau_type.into(),
726            tau.data.as_ptr().cast(),
727            t_type.into(),
728            t.data.as_ptr().cast_mut().cast(),
729            to_i64(t.leading_dimension, "ldt")?,
730            compute_type.into(),
731            &raw mut device_bytes,
732            &raw mut host_bytes,
733        ))?;
734    }
735    Ok(WorkspaceSizes::new(
736        to_usize(device_bytes, "device workspace size")?,
737        to_usize(host_bytes, "host workspace size")?,
738    ))
739}
740
741/// Use the matching buffer-size helper to calculate the sizes needed for pre-allocated workspace.
742///
743/// Forms the triangular factor `T` of a real block reflector `H` of order `n`,
744/// which is defined as a product of `k` elementary reflectors.
745///
746/// Only [`StorevMode::Columnwise`] storage is supported. This means the vector
747/// defining the elementary reflector `H(i)` is stored in the `i`th column of
748/// `V`, and $H = I - V \cdot T \cdot V^{T}$ ($H = I - V \cdot T \cdot V^{H}$
749/// for complex types).
750///
751/// Provide device and host workspace through `workspace`.
752/// Use [`xlarft_buffer_size`] to determine the required sizes for
753/// `workspace.device` and `workspace.host`.
754///
755/// Currently, only the `n >= k` scenario is supported.
756///
757/// The generic cuSOLVER routine has four data types:
758///
759/// [`xlarft`] only supports the following four combinations.
760///
761/// **Valid combinations of data types and compute types**
762///
763/// | **data_type_v** | **data_type_tau** | **data_type_t** | **compute_type** | **Meaning** |
764/// | --- | --- | --- | --- | --- |
765/// | [`DataType::F32`] | [`DataType::F32`] | [`DataType::F32`] | [`DataType::F32`] | `SLARFT` |
766/// | [`DataType::F64`] | [`DataType::F64`] | [`DataType::F64`] | [`DataType::F64`] | `DLARFT` |
767/// | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | [`DataType::ComplexF32`] | `CLARFT` |
768/// | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | [`DataType::ComplexF64`] | `ZLARFT` |
769///
770/// # Errors
771///
772/// Returns an error if cuSOLVER has not been initialized, if the
773/// reflector dimensions or storage mode are invalid, or if cuSOLVER reports an
774/// internal failure.
775pub fn xlarft<TV: DataTypeLike, TTau: DataTypeLike, TT: DataTypeLike>(
776    ctx: &Context,
777    params: &Params,
778    direct: DirectMode,
779    storev: StorevMode,
780    n: usize,
781    k: usize,
782    v: MatrixRef<'_, TV>,
783    tau: VectorRef<'_, TTau>,
784    t: MatrixMut<'_, TT>,
785    compute_type: DataType,
786    workspace: ByteWorkspaceMut<'_>,
787) -> Result<()> {
788    ctx.bind()?;
789    let v_type = TV::data_type();
790    let tau_type = TTau::data_type();
791    let t_type = TT::data_type();
792    validate_xlarft_inputs(
793        n,
794        k,
795        storev,
796        v.data.byte_len(),
797        v.leading_dimension,
798        v_type,
799        tau.data.byte_len(),
800        tau_type,
801        t.data.byte_len(),
802        t.leading_dimension,
803        t_type,
804    )?;
805    let workspace_sizes = xlarft_buffer_size(
806        ctx,
807        params,
808        direct,
809        storev,
810        n,
811        k,
812        v,
813        tau,
814        t.as_ref(),
815        compute_type,
816    )?;
817    require_workspace_bytes(workspace.device.byte_len(), workspace_sizes.device_bytes)?;
818    require_host_workspace(workspace.host.len(), workspace_sizes.host_bytes)?;
819    unsafe {
820        try_ffi!(sys::cusolverDnXlarft(
821            ctx.as_raw(),
822            params.as_raw(),
823            direct.into(),
824            storev.into(),
825            to_i64(n, "n")?,
826            to_i64(k, "k")?,
827            v_type.into(),
828            v.data.as_ptr().cast(),
829            to_i64(v.leading_dimension, "ldv")?,
830            tau_type.into(),
831            tau.data.as_ptr().cast(),
832            t_type.into(),
833            t.data.as_mut_ptr().cast(),
834            to_i64(t.leading_dimension, "ldt")?,
835            compute_type.into(),
836            workspace.device.as_mut_ptr().cast(),
837            workspace_sizes.device_bytes as _,
838            workspace.host.as_mut_ptr().cast(),
839            workspace_sizes.host_bytes as _,
840        ))?;
841    }
842    Ok(())
843}