Skip to main content

singe_cusolver/svd/
info.rs

1use std::ptr;
2
3use crate::{
4    context::Context,
5    error::{Error, Result},
6    sys, try_ffi,
7};
8
9#[derive(Debug)]
10pub struct GesvdjInfo {
11    handle: sys::gesvdjInfo_t,
12}
13
14// gesvdj info handles store solver options and expose mutation only through
15// &mut self, so immutable sharing is allowed.
16unsafe impl Send for GesvdjInfo {}
17unsafe impl Sync for GesvdjInfo {}
18
19impl GesvdjInfo {
20    /// Creates `gesvdj` and `gesvdjBatched` parameter storage with default values.
21    ///
22    /// # Errors
23    ///
24    /// Returns an error if cuSOLVER cannot allocate the parameter storage or if
25    /// it does not return a valid handle.
26    pub fn create() -> Result<Self> {
27        let mut handle = ptr::null_mut();
28        unsafe {
29            try_ffi!(sys::cusolverDnCreateGesvdjInfo(&raw mut handle))?;
30        }
31
32        if handle.is_null() {
33            return Err(Error::NullHandle);
34        }
35
36        Ok(Self { handle })
37    }
38
39    /// Configures the `gesvdj` tolerance.
40    ///
41    /// # Errors
42    ///
43    /// Returns an error if cuSOLVER rejects `tolerance`.
44    pub fn set_tolerance(&mut self, tolerance: f64) -> Result<()> {
45        unsafe {
46            try_ffi!(sys::cusolverDnXgesvdjSetTolerance(self.as_raw(), tolerance,))?;
47        }
48        Ok(())
49    }
50
51    /// Configures the maximum number of `gesvdj` sweeps.
52    /// The default value is 100.
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if cuSOLVER rejects `max_sweeps`.
57    pub fn set_max_sweeps(&mut self, max_sweeps: i32) -> Result<()> {
58        unsafe {
59            try_ffi!(sys::cusolverDnXgesvdjSetMaxSweeps(
60                self.as_raw(),
61                max_sweeps,
62            ))?;
63        }
64        Ok(())
65    }
66
67    /// If `sort_eigenvalues` is false, the singular values are not sorted.
68    /// This setting only applies to `gesvdjBatched`.
69    /// `gesvdj` always sorts singular values in descending order.
70    /// By default, singular values are always sorted in descending order.
71    ///
72    /// # Errors
73    ///
74    /// Returns an error if cuSOLVER rejects the sort setting.
75    pub fn set_sort_eigenvalues(&mut self, sort_eigenvalues: bool) -> Result<()> {
76        unsafe {
77            try_ffi!(sys::cusolverDnXgesvdjSetSortEig(
78                self.as_raw(),
79                i32::from(sort_eigenvalues),
80            ))?;
81        }
82        Ok(())
83    }
84
85    /// Returns the Frobenius norm of the internal residual reported by `gesvdj`.
86    /// Not the Frobenius norm of the exact residual.
87    ///
88    /// This accessor does not support `gesvdjBatched`.
89    /// Calling this after `gesvdjBatched` returns [`crate::error::Status::NotSupported`].
90    ///
91    /// # Errors
92    ///
93    /// Returns an error if the info handle was used with `gesvdjBatched`,
94    /// which does not report a residual.
95    pub fn residual(&self, ctx: &Context) -> Result<f64> {
96        ctx.bind()?;
97
98        let mut residual = 0.0;
99        unsafe {
100            try_ffi!(sys::cusolverDnXgesvdjGetResidual(
101                ctx.as_raw(),
102                self.as_raw(),
103                &raw mut residual,
104            ))?;
105        }
106        Ok(residual)
107    }
108
109    /// Returns the number of executed `gesvdj` sweeps.
110    /// This accessor does not support `gesvdjBatched`.
111    /// Calling this after `gesvdjBatched` returns [`crate::error::Status::NotSupported`].
112    ///
113    /// # Errors
114    ///
115    /// Returns an error if the info handle was used with `gesvdjBatched`,
116    /// which does not report a sweep count.
117    pub fn executed_sweeps(&self, ctx: &Context) -> Result<i32> {
118        ctx.bind()?;
119
120        let mut sweeps = 0;
121        unsafe {
122            try_ffi!(sys::cusolverDnXgesvdjGetSweeps(
123                ctx.as_raw(),
124                self.as_raw(),
125                &raw mut sweeps,
126            ))?;
127        }
128        Ok(sweeps)
129    }
130
131    pub fn as_raw(&self) -> sys::gesvdjInfo_t {
132        self.handle
133    }
134
135    /// Takes ownership of a raw cuSOLVER `gesvdj` info handle.
136    ///
137    /// # Safety
138    ///
139    /// `handle` must be a valid `gesvdjInfo_t` created by cuSOLVER. The
140    /// returned wrapper takes ownership and will destroy it with
141    /// `cusolverDnDestroyGesvdjInfo`; no other owner may destroy or keep using it.
142    pub unsafe fn from_raw(handle: sys::gesvdjInfo_t) -> Result<Self> {
143        if handle.is_null() {
144            return Err(Error::NullHandle);
145        }
146        Ok(Self { handle })
147    }
148
149    /// Releases ownership and returns the raw cuSOLVER `gesvdj` info handle.
150    ///
151    /// The caller becomes responsible for destroying the handle.
152    pub fn into_raw(self) -> sys::gesvdjInfo_t {
153        let handle = self.handle;
154        std::mem::forget(self);
155        handle
156    }
157}
158
159impl Drop for GesvdjInfo {
160    fn drop(&mut self) {
161        unsafe {
162            if let Err(err) = try_ffi!(sys::cusolverDnDestroyGesvdjInfo(self.handle)) {
163                #[cfg(debug_assertions)]
164                eprintln!("failed to destroy cusolver gesvdj info: {err}");
165            }
166        }
167    }
168}