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}