Skip to content

Commit b4b689f

Browse files
committed
Improve documentation for SVD decomposition
1 parent 654fe04 commit b4b689f

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

ndarray-linalg/src/lobpcg/lobpcg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
///! Locally Optimal Block Preconditioned Conjugated
22
///!
33
///! This module implements the Locally Optimal Block Preconditioned Conjugated (LOBPCG) algorithm,
4-
///which can be used as a solver for large symmetric positive definite eigenproblems.
4+
///which can be used as a solver for large symmetric eigenproblems.
55
use crate::error::{LinalgError, Result};
66
use crate::{cholesky::*, close_l2, eigh::*, norm::*, triangular::*};
77
use cauchy::Scalar;

ndarray-linalg/src/lobpcg/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
//! Decomposition with LOBPCG
2+
//!
3+
//! Locally Optimal Block Preconditioned Conjugate Gradient (LOBPCG) is a matrix-free method for
4+
//! finding the large (or smallest) eigenvalues and the corresponding eigenvectors of a symmetric
5+
//! eigenvalue problem
6+
//! ```
7+
//! A x = lambda x
8+
//! ```
9+
//! where A is symmetric and (x, lambda) the solution. It has the following advantages:
10+
//! * matrix free: does not require storing the coefficient matrix explicitely and only evaluates
11+
//! matrix-vector products.
12+
//! * factorization-free: does not require any matrix decomposition
13+
//! * linear-convergence: theoretically guaranteed and practically observed
14+
//!
15+
//! See also the wikipedia article at [LOBPCG](https://en.wikipedia.org/wiki/LOBPCG)
16+
//!
117
mod eig;
218
mod lobpcg;
319
mod svd;

ndarray-linalg/src/lobpcg/svd.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub struct TruncatedSvdResult<A> {
2424
}
2525

2626
impl<A: Float + PartialOrd + DivAssign<A> + 'static + MagnitudeCorrection> TruncatedSvdResult<A> {
27-
/// Returns singular values ordered by magnitude with indices.
27+
/// Returns singular values ordered by magnitude with indices
2828
fn singular_values_with_indices(&self) -> (Array1<A>, Vec<usize>) {
2929
// numerate eigenvalues
3030
let mut a = self.eigvals.iter().enumerate().collect::<Vec<_>>();
@@ -90,7 +90,7 @@ impl<A: Float + PartialOrd + DivAssign<A> + 'static + MagnitudeCorrection> Trunc
9090
/// Truncated singular value decomposition
9191
///
9292
/// Wraps the LOBPCG algorithm and provides convenient builder-pattern access to
93-
/// parameter like maximal iteration, precision and constraint matrix.
93+
/// parameter like maximal iteration, precision and contrain matrix.
9494
pub struct TruncatedSvd<A: Scalar> {
9595
order: Order,
9696
problem: Array2<A>,
@@ -99,6 +99,11 @@ pub struct TruncatedSvd<A: Scalar> {
9999
}
100100

101101
impl<A: Float + Scalar + ScalarOperand + Lapack + PartialOrd + Default> TruncatedSvd<A> {
102+
/// Create a new truncated SVD problem
103+
///
104+
/// # Parameters
105+
/// * `problem`: rectangular matrix which is decomposed
106+
/// * `order`: whether to return large or small (close to zero) singular values
102107
pub fn new(problem: Array2<A>, order: Order) -> TruncatedSvd<A> {
103108
TruncatedSvd {
104109
precision: 1e-5,
@@ -108,19 +113,48 @@ impl<A: Float + Scalar + ScalarOperand + Lapack + PartialOrd + Default> Truncate
108113
}
109114
}
110115

116+
/// Set the required precision of the solution
117+
///
118+
/// The precision is, in the context of SVD, the square-root precision of the underlying
119+
/// eigenproblem solution. The eigenproblem-precision is used to check the L2 error of each
120+
/// eigenvector and stops its optimization when the required precision is reached.
111121
pub fn precision(mut self, precision: f32) -> Self {
112122
self.precision = precision;
113123

114124
self
115125
}
116126

127+
/// Set the maximal number of iterations
128+
///
129+
/// The LOBPCG is an iterative approach to eigenproblems and stops when this maximum
130+
/// number of iterations are reached.
117131
pub fn maxiter(mut self, maxiter: usize) -> Self {
118132
self.maxiter = maxiter;
119133

120134
self
121135
}
122136

123-
// calculate the eigenvalue decomposition
137+
/// Calculate the singular value decomposition
138+
///
139+
/// # Parameters
140+
///
141+
/// * `num`: number of singular-value/vector pairs, ordered by magnitude
142+
///
143+
/// # Example
144+
///
145+
/// ```rust
146+
/// use ndarray::{arr1, Array2};
147+
/// use ndarray_linalg::{TruncatedSvd, TruncatedOrder};
148+
///
149+
/// let diag = arr1(&[1., 2., 3., 4., 5.]);
150+
/// let a = Array2::from_diag(&diag);
151+
///
152+
/// let eig = TruncatedSvd::new(a, TruncatedOrder::Largest)
153+
/// .precision(1e-5)
154+
/// .maxiter(500);
155+
///
156+
/// let res = eig.decompose(3);
157+
/// ```
124158
pub fn decompose(self, num: usize) -> Result<TruncatedSvdResult<A>> {
125159
if num < 1 {
126160
panic!("The number of singular values to compute should be larger than zero!");

0 commit comments

Comments
 (0)