Added SVD decomposition function matrix_svd for the real matricies

Changes to be committed:
modified:   dspl/src/blas.h
modified:   dspl/src/matrix.c
new file:   examples/src/matrix_svd_test.c
modified:   include/dspl.c
modified:   include/dspl.h
pull/6/merge
Dsplib 2020-10-16 16:26:47 +03:00
rodzic 7af0e61ce3
commit f848c84fac
5 zmienionych plików z 176 dodań i 46 usunięć

Wyświetl plik

@ -362,5 +362,10 @@ int FORTRAN_FUNC(xher2m)(const char*, const char*, const char*, const int*, cons
void FORTRAN_FUNC(zgees)(const char*, const char*, void*, int*, complex_t*, int*, int*, complex_t*, complex_t*, int*, complex_t*, int*, double*, int*, int*);
void FORTRAN_FUNC(dgesdd)(const char*, int*, int*, double*, int*, double*,
double*, int*, double*, int*, double*,
int*, int*, int*);
#endif

Wyświetl plik

@ -199,6 +199,8 @@ int DSPL_API matrix_eye_cmplx(complex_t* a, int n, int m)
#ifdef DOXYGEN_ENGLISH
#endif
@ -226,6 +228,57 @@ int DSPL_API matrix_mul(double* a, int na, int ma,
#ifdef DOXYGEN_ENGLISH
#endif
#ifdef DOXYGEN_RUSSIAN
#endif
int DSPL_API matrix_svd(double* a, int n, int m,
double* u, double* s, double* vt, int* info)
{
char jobz = 'A';
double* work = NULL;
int* iwork = NULL;
int lwork, mn, mx, err;
int pi;
if(!a || !u || !s || !vt)
return ERROR_PTR;
if(n < 1 || m < 1)
return ERROR_SIZE;
if(n > m)
{
mn = m;
mx = n;
}
else
{
mn = n;
mx = m;
}
err = RES_OK;
lwork = 4 * mn * mn + 6 * mn + mx;
work = (double*) malloc(lwork*sizeof(double));
iwork = (int*) malloc(8*mn*sizeof(int));
dgesdd_(&jobz, &n, &m, a, &n, s, u, &n, vt, &m, work, &lwork, iwork, &pi);
if(info)
*info = pi;
if(pi)
err = ERROR_LAPACK;
if(work)
free(work);
if(iwork)
free(iwork);
return err;
}
#ifdef DOXYGEN_ENGLISH
#endif

Wyświetl plik

@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dspl.h"
#define N 4
#define M 3
int main(int argc, char* argv[])
{
void* handle; /* DSPL handle */
handle = dspl_load(); /* Load DSPL function */
/* Matrix
A = [ 1 2 3;
3 4 5;
2 0 1;
2 -1 0;];
in array a by columns
*/
double a[N*M] = { 1, 3, 2, 2, 2, 4, 0, -1, 3, 5, 1, 0};
double u[N*N]; /* left orthogonal matrix U */
double s[M]; /* Singular values diagonal */
double vt[M*M];/* transposed left orthogonal matrix V^T */
double ur[N*M] = {0}; /* matrix UR = U*S */
double ar[N*M]; /* AR = UR * V^T */
int err, info, i, j, mn;
/* print input matrix */
matrix_print(a, N, M, "A", "%8.2f");
/* SVD decomposition A = U*S*V^T */
/*-----------------------------------------------------*/
err = matrix_svd(a, N, M, u, s, vt, &info);
if(err != RES_OK)
printf("err = %.8x info = %d\n", err, info);
/* Print SVD decomposition */
matrix_print(u, N, N, "U", "%8.4f");
matrix_print(vt, M, M, "V^T", "%8.4f");
matrix_print(s, M, 1, "S", "%8.6f");
/* SVD reconstruction AR = U*S*V^T */
/*-----------------------------------------------------*/
/* step 1: UR = U*S.
We can process this by columns
because S is diagonal
*/
mn = (M > N) ? N : M;
for(i = 0; i < mn; i++)
for(j = 0; j < N; j++)
ur[j + i*N] = u[j + i*N] * s[i];
/* step 2: AR = U * S * V^T */
matrix_mul(ur, N, M, vt, M, M, ar);
matrix_print(ar, N, M, "AR = U*S*V^T", "%8.2f");
dspl_free(handle); /* free dspl handle */
return 0;
}

Wyświetl plik

@ -139,6 +139,7 @@ p_matrix_eye_cmplx matrix_eye_cmplx ;
p_matrix_mul matrix_mul ;
p_matrix_print matrix_print ;
p_matrix_print_cmplx matrix_print_cmplx ;
p_matrix_svd matrix_svd ;
p_matrix_transpose matrix_transpose ;
p_matrix_transpose_cmplx matrix_transpose_cmplx ;
p_matrix_transpose_hermite matrix_transpose_hermite ;
@ -351,6 +352,7 @@ void* dspl_load()
LOAD_FUNC(matrix_mul);
LOAD_FUNC(matrix_print);
LOAD_FUNC(matrix_print_cmplx);
LOAD_FUNC(matrix_svd);
LOAD_FUNC(matrix_transpose);
LOAD_FUNC(matrix_transpose_cmplx);
LOAD_FUNC(matrix_transpose_hermite);
@ -440,8 +442,6 @@ void* dspl_load()
void dspl_free(void* handle)
{
#ifdef WIN_OS

Wyświetl plik

@ -1228,6 +1228,14 @@ DECLARE_FUNC(int, matrix_print_cmplx, complex_t* a
COMMA const char* name
COMMA const char* format);
/*----------------------------------------------------------------------------*/
DECLARE_FUNC(int, matrix_svd, double* a
COMMA int n
COMMA int m
COMMA double* u
COMMA double* s
COMMA double* vt
COMMA int* info);
/*----------------------------------------------------------------------------*/
DECLARE_FUNC(int, matrix_transpose, double* a
COMMA int n
COMMA int m
@ -1563,49 +1571,6 @@ DECLARE_FUNC(int, xcorr_cmplx, complex_t* x
#endif
#ifdef DOXYGEN_ENGLISH
/*! ****************************************************************************
\ingroup SYS_LOADING_GROUP
\fn void dspl_free(void* handle)
\brief Cleans up the previously linked DSPL-2.0 dynamic library.
This cross-platform function clears the library `libdspl.dll` in
Windows system and from the library `libdspl.so` on the Linux system.
After cleaning the library, all functions will become unavailable.
\param [in] handle
Handle of the previously linked DSPL-2.0 library. \n
This pointer can be `NULL`, in this case no action
are being produced.
\author Bakhurin Sergey. www.dsplib.org
***************************************************************************** */
#endif
#ifdef DOXYGEN_RUSSIAN
/*! ****************************************************************************
\ingroup SYS_LOADING_GROUP
\fn void dspl_free(void* handle)
\brief Очищает связанную ранее динамическую библиотеку DSPL-2.0.
Данная кроссплатформенная функция производит очистку библиотеки `libdspl.dll` в
системе Windows и с библиотеки `libdspl.so` в системе Linux.
После очистки библиотеки все функции станут недоступны.
\param[in] handle
Хэндл прилинкованной ранее библиотеки DSPL-2.0. \n
Данный указатель может быть `NULL`, в этом случае никакие действия не
производятся.\n\n
\author Бахурин Сергей. www.dsplib.org
**************************************************************************** */
#endif
void* dspl_load();
#ifdef DOXYGEN_ENGLISH
/*! ****************************************************************************
\ingroup SYS_LOADING_GROUP
@ -1694,7 +1659,7 @@ int main(int argc, char* argv[])
void* hdspl; // DSPL хэндл
hdspl = dspl_load(); // Динамическая линковка
// Проверяем указатель. Если `NULLL`, то линковка прошла неудачно
// Проверяем указатель. Если `NULL`, то линковка прошла неудачно
if(!hdspl)
{
printf("libdspl loading error!\n");
@ -1714,6 +1679,48 @@ int main(int argc, char* argv[])
\author Бахурин Сергей. www.dsplib.org
***************************************************************************** */
#endif
void* dspl_load();
#ifdef DOXYGEN_ENGLISH
/*! ****************************************************************************
\ingroup SYS_LOADING_GROUP
\fn void dspl_free(void* handle)
\brief Cleans up the previously linked DSPL-2.0 dynamic library.
This cross-platform function clears the library `libdspl.dll` in
Windows system and from the library `libdspl.so` on the Linux system.
After cleaning the library, all functions will become unavailable.
\param [in] handle
Handle of the previously linked DSPL-2.0 library. \n
This pointer can be `NULL`, in this case no action
are being produced.
\author Bakhurin Sergey. www.dsplib.org
***************************************************************************** */
#endif
#ifdef DOXYGEN_RUSSIAN
/*! ****************************************************************************
\ingroup SYS_LOADING_GROUP
\fn void dspl_free(void* handle)
\brief Очищает связанную ранее динамическую библиотеку DSPL-2.0.
Данная кроссплатформенная функция производит очистку библиотеки `libdspl.dll` в
системе Windows и с библиотеки `libdspl.so` в системе Linux.
После очистки библиотеки все функции станут недоступны.
\param[in] handle
Хэндл прилинкованной ранее библиотеки DSPL-2.0. \n
Данный указатель может быть `NULL`, в этом случае никакие действия не
производятся.\n\n
\author Бахурин Сергей. www.dsplib.org
**************************************************************************** */
#endif
void dspl_free(void* handle);