Skip to content

Commit

Permalink
Merge pull request #84 from cpmech/add-lapack-eigen-functions
Browse files Browse the repository at this point in the history
Add lapack eigen functions
  • Loading branch information
cpmech authored Mar 16, 2024
2 parents 0fc4f4a + 1030a3a commit f4f3ba0
Show file tree
Hide file tree
Showing 20 changed files with 2,704 additions and 41 deletions.
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"cSpell.words": [
"aiᵢⱼ",
"alphai",
"alphar",
"archlinux",
"Arenstorf",
"Arioli",
Expand All @@ -18,6 +20,7 @@
"dgesvd",
"dgetrf",
"dgetri",
"dggev",
"dgssvx",
"Dᵢⱼₖₗ",
"dopri",
Expand Down Expand Up @@ -75,23 +78,28 @@
"rowcoliter",
"rowcolrig",
"rustup",
"rwork",
"Schur",
"substeps",
"Teukolsky",
"tgamma",
"tocsc",
"tocsr",
"tridiagonal",
"udyad",
"unsym",
"Verner",
"Vetterling",
"zcopy",
"zgeev",
"zgemm",
"zgemv",
"zgesv",
"zgesvd",
"zgetrf",
"zgetri",
"zggev",
"zheev",
"zherk",
"zlange",
"ZMUMPS",
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ See also:
* [russell_lab/examples](https://github.com/cpmech/russell/tree/main/russell_lab/examples)
* [russell_sparse/examples](https://github.com/cpmech/russell/tree/main/russell_sparse/examples)

**Note:** For the functions dealing with complex numbers, the following line must be added to all derived code:

```rust
use num_complex::Complex64;
```

This line will bring `Complex64` to the scope. For convenience the (russell_lab) macro `cpx!` may be used to allocate complex numbers.

### Compute a singular value decomposition

```rust
Expand Down
11 changes: 11 additions & 0 deletions russell_lab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ _This crate is part of [Russell - Rust Scientific Library](https://github.com/cp
* [Introduction](#introduction)
* [Installation](#debian)
* [Setting Cargo.toml](#cargo)
* [Complex numbers](#complex-numbers)
* [Examples](#examples)
* [About the column major representation](#col-major)
* [Benchmarks](#benchmarks)
Expand Down Expand Up @@ -50,6 +51,16 @@ This crate depends on an efficient BLAS library such as [OpenBLAS](https://githu
russell_lab = "*"
```

## <a name="complex-numbers"></a> Complex numbers

**Note:** For the functions dealing with complex numbers, the following line must be added to all derived code:

```rust
use num_complex::Complex64;
```

This line will bring `Complex64` to the scope. For convenience the (russell_lab) macro `cpx!` may be used to allocate complex numbers.

## <a name="examples"></a> Examples

See also:
Expand Down
128 changes: 128 additions & 0 deletions russell_lab/c_code/interface_blas.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
#define FN_DPOTRF dpotrf_
#define FN_DSYEV dsyev_
#define FN_DGEEV dgeev_
#define FN_ZGEEV zgeev_
#define FN_ZHEEV zheev_
#define FN_DGGEV dggev_
#define FN_ZGGEV zggev_
#define FN_DGESVD dgesvd_
#define FN_ZGESVD zgesvd_
#define FN_DGETRF dgetrf_
#define FN_DGETRI dgetri_
#define FN_ZGETRF zgetrf_
Expand All @@ -27,7 +32,12 @@
#define FN_DPOTRF LAPACK_dpotrf
#define FN_DSYEV LAPACK_dsyev
#define FN_DGEEV LAPACK_dgeev
#define FN_ZGEEV LAPACK_zgeev
#define FN_ZHEEV LAPACK_zheev
#define FN_DGGEV LAPACK_dggev
#define FN_ZGGEV LAPACK_zggev
#define FN_DGESVD LAPACK_dgesvd
#define FN_ZGESVD LAPACK_zgesvd
#define FN_DGETRF LAPACK_dgetrf
#define FN_DGETRI LAPACK_dgetri
#define FN_ZGETRF LAPACK_zgetrf
Expand Down Expand Up @@ -185,6 +195,96 @@ void c_dgeev(C_BOOL calc_vl,
FN_DGEEV(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info);
}

// Computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE matrices
// <https://www.netlib.org/lapack/explore-html/dd/dba/zgeev_8f.html>
void c_zgeev(
C_BOOL calc_vl,
C_BOOL calc_vr,
const int32_t *n,
COMPLEX64 *a,
const int32_t *lda,
COMPLEX64 *w,
COMPLEX64 *vl,
const int32_t *ldvl,
COMPLEX64 *vr,
const int32_t *ldvr,
COMPLEX64 *work,
const int32_t *lwork,
double *rwork,
int32_t *info) {
const char *jobvl = calc_vl == C_TRUE ? "V" : "N";
const char *jobvr = calc_vr == C_TRUE ? "V" : "N";
FN_ZGEEV(jobvl, jobvr, n, a, lda, w, vl, ldvl, vr, ldvr, work, lwork, rwork, info);
}

// Computes the eigenvalues and, optionally, the left and/or right eigenvectors for HE matrices
// <https://www.netlib.org/lapack/explore-html/d6/dee/zheev_8f.html>
void c_zheev(
C_BOOL calc_v,
C_BOOL upper,
int32_t const *n,
COMPLEX64 *a,
int32_t const *lda,
double *w,
COMPLEX64 *work,
int32_t const *lwork,
double *rwork,
int32_t *info) {
const char *jobz = calc_v == C_TRUE ? "V" : "N";
const char *uplo = upper == C_TRUE ? "U" : "L";
FN_ZHEEV(jobz, uplo, n, a, lda, w, work, lwork, rwork, info);
}

// Computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE matrices
// <https://www.netlib.org/lapack/explore-html/d9/d52/dggev_8f.html>
void c_dggev(
C_BOOL calc_vl,
C_BOOL calc_vr,
const int32_t *n,
double *a,
const int32_t *lda,
double *b,
const int32_t *ldb,
double *alphar,
double *alphai,
double *beta,
double *vl,
const int32_t *ldvl,
double *vr,
const int32_t *ldvr,
double *work,
const int32_t *lwork,
int32_t *info) {
const char *jobvl = calc_vl == C_TRUE ? "V" : "N";
const char *jobvr = calc_vr == C_TRUE ? "V" : "N";
FN_DGGEV(jobvl, jobvr, n, a, lda, b, ldb, alphar, alphai, beta, vl, ldvl, vr, ldvr, work, lwork, info);
}

// Computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE matrices
// <https://www.netlib.org/lapack/explore-html/d3/d47/zggev_8f.html>
void c_zggev(
C_BOOL calc_vl,
C_BOOL calc_vr,
const int32_t *n,
COMPLEX64 *a,
const int32_t *lda,
COMPLEX64 *b,
const int32_t *ldb,
COMPLEX64 *alpha,
COMPLEX64 *beta,
COMPLEX64 *vl,
const int32_t *ldvl,
COMPLEX64 *vr,
const int32_t *ldvr,
COMPLEX64 *work,
const int32_t *lwork,
double *rwork,
int32_t *info) {
const char *jobvl = calc_vl == C_TRUE ? "V" : "N";
const char *jobvr = calc_vr == C_TRUE ? "V" : "N";
FN_ZGGEV(jobvl, jobvr, n, a, lda, b, ldb, alpha, beta, vl, ldvl, vr, ldvr, work, lwork, rwork, info);
}

// Computes the singular value decomposition (SVD)
// <https://www.netlib.org/lapack/explore-html/d8/d2d/dgesvd_8f.html>
void c_dgesvd(int32_t jobu_code,
Expand Down Expand Up @@ -212,6 +312,34 @@ void c_dgesvd(int32_t jobu_code,
FN_DGESVD(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work, lwork, info);
}

// Computes the singular value decomposition (SVD)
// <https://www.netlib.org/lapack/explore-html/d6/d42/zgesvd_8f.html>
void c_zgesvd(int32_t jobu_code,
int32_t jobvt_code,
const int32_t *m,
const int32_t *n,
COMPLEX64 *a,
const int32_t *lda,
double *s,
COMPLEX64 *u,
const int32_t *ldu,
COMPLEX64 *vh,
const int32_t *ldvt,
COMPLEX64 *work,
const int32_t *lwork,
double *rwork,
int32_t *info) {
const char *jobu = jobu_code == SVD_CODE_A ? "A"
: jobu_code == SVD_CODE_S ? "S"
: jobu_code == SVD_CODE_O ? "O"
: "N";
const char *jobvt = jobvt_code == SVD_CODE_A ? "A"
: jobvt_code == SVD_CODE_S ? "S"
: jobvt_code == SVD_CODE_O ? "O"
: "N";
FN_ZGESVD(jobu, jobvt, m, n, a, lda, s, u, ldu, vh, ldvt, work, lwork, rwork, info);
}

// Computes the LU factorization of a general (m,n) matrix
// <https://www.netlib.org/lapack/explore-html/d3/d6a/dgetrf_8f.html>
void c_dgetrf(const int32_t *m,
Expand Down
36 changes: 36 additions & 0 deletions russell_lab/examples/temp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use num_complex::Complex64;
use russell_lab::*;

fn main() -> Result<(), StrError> {
// matrix
let data = [
[cpx!(1.0, 1.0), cpx!(2.0, -1.0), cpx!(3.0, 0.0)],
[cpx!(2.0, -1.0), cpx!(4.0, 1.0), cpx!(5.0, -1.0)],
[cpx!(3.0, 0.0), cpx!(5.0, -1.0), cpx!(6.0, 1.0)],
];

let mut a = ComplexMatrix::from(&data);
let a_copy = ComplexMatrix::from(&data);

// allocate output data
let (m, n) = a.dims();
let min_mn = if m < n { m } else { n };
let mut s = Vector::new(min_mn);
let mut u = ComplexMatrix::new(m, m);
let mut vh = ComplexMatrix::new(n, n);

// calculate SVD
complex_mat_svd(&mut s, &mut u, &mut vh, &mut a).unwrap();

// check SVD
let mut usv = ComplexMatrix::new(m, n);
for i in 0..m {
for j in 0..n {
for k in 0..min_mn {
usv.add(i, j, u.get(i, k) * s[k] * vh.get(k, j));
}
}
}
complex_mat_approx_eq(&usv, &a_copy, 1e-14);
Ok(())
}
8 changes: 8 additions & 0 deletions russell_lab/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
//! * Reading writing files ([read_table()]) , linspace ([NumVector::linspace()]), grid generators ([generate2d()]), [generate3d()]), [linear_fitting()], [Stopwatch] and more
//! * Checking results, comparing float point numbers, and verifying the correctness of derivatives; see [crate::check]
//!
//! **Note:** For the functions dealing with complex numbers, the following line must be added to all derived code:
//!
//! ```
//! use num_complex::Complex64;
//! ```
//!
//! This line will bring [num_complex::Complex64] to the scope. For convenience the (russell_lab) macro [crate::cpx!] may be used to allocate complex numbers.
//!
//! # Example - Cholesky factorization
//!
//! ```
Expand Down
Loading

0 comments on commit f4f3ba0

Please sign in to comment.