ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Lapack 科学计算包

2022-02-20 13:32:58  阅读:403  来源: 互联网

标签:LDA lapack Lapack 科学计算 矩阵 int 数组 double


本文整理了科学计算包 Lapack 的安装过程和使用规范。

 

环境包

需要安装 gfortran 和 cmake

sudo apt-get install gfortran

 

BLAS 库和 CBLAS 接口

BLAS(basic linear algebra subroutine) 是一系列基本线性代数运算函数的接口(interface)标准。这里的线性代数运算是指例如矢量的线性组合,矩阵乘以矢量,矩阵乘以矩阵等。接口在这里指的是诸如哪个函数名实现什么功能,有几个输入和输出变量,分别是什么。

BLAS 被广泛用于科学计算和工业界,已成为业界标准。在更高级的语言和库中,即使我们不直接使用 BLAS 接口,它们也是通过调用 BLAS 来实现的(如 Matlab 中的各种矩阵运算)。

BLAS 原本是用 Fortran 语言写的,但后来也产生了 C 语言的版本 cBLAS , 接口与 Fortran 的略有不同(例如使用指针传递数组),但大同小异。

注意 BLAS 是一个接口的标准而不是某种具体实现(implementation),简单来说,就是不同的作者可以各自写出不同版本的 BLAS 库, 实现同样的接口和功能,但每个函数内部的算法可以不同。这些不同导致了不同版本的 BLAS 在不同机器上运行的速度也不同。

BLAS 的官网是 Netlib ,可以浏览完整的说明文档以及下载源代码。这个版本的 BLAS 被称为 reference BLAS,运行速度较慢,通常被其他版本用于衡量性能。对于 Intel CPU 的计算机,性能最高的是 Intel 的 MKL (Math Kernel Library) 中提供的 BLAS 。 MKL 虽然不是一个开源软件,但目前可以免费下载使用。如果想要免费开源的版本,可以尝试 OpenBlas 或者 ATLAS2 ,另外,无论是否使用 MKL,BLAS 的文档都推荐看 MKL 的相关页面

 

安装 blas

wget http://www.netlib.org/blas/blas.tgz
tar -xzvf blas.tgz
cd BLAS-3.10.0
make
sudo cp blas_LINUX.a /usr/local/lib/libblas.a
# 将 blas_LINUX.a 复制到系统库中
# 也可以使用 ln -sf ~/BLAS-3.10.0/blas_LINUX.a /usr/local/lib/libblas.a 进行链接

 

安装 cblas

wget http://www.netlib.org/blas/blast-forum/cblas.tgz
tar -xavf cblas.tgz
cd CBLAS
cp Makefile.LINUX Makefile.in
# 修改 Makefile.in ,指出 libblas.a 的位置
# BLLIB = /usr/local/lib/libblas.a
make
sudo cp lib/cblas_LINUX.a /usr/local/lib/libcblas.a
# 将 cblas_LINUX.a 复制到系统库中

 

安装 LAPACK

由于 github 官网链接下载太慢,直接在 http://www.netlib.org/lapack/ 中寻找最新版本下载

tar -xzvf lapack-3.10.0.tar.gz 
cd lapack-3.10.0 
cp make.inc.example make.inc 
# 修改其中 BLASLIB 和 CBLASLIB 路径 
make lib
sudo cp liblapack.a /usr/local/lib/ 
sudo cp libtmglib.a /usr/local/lib/
# 将 liblapack.a 、libtmglib.a 复制到系统库中

cd TESTING
make # 编译 lapack 文件
cd LAPACKE # 进入 LAPACKE 文件夹
make # 编译 lapacke
cp include/*.h /usr/local/include/
# 复制全部头文件到系统头文件目录
cp .. # 返回上一级
cp *.a /usr/local/lib/ 
# 复制全部库文件到系统库目录

 

基本框架

概述

LAPACK API 支持两种形式:标准的 ANSI C 和标准的 FORTRAN

每个 LAPACK 例程都有四个形式:

精度 例程前缀
REAL S
REAL DOUBLE D
COMPLEX C
COMPLEX DOUBLE Z

 

函数命名规则

  • LAPACK 中的每个函数名已经说明了该函数的使用规则
  • 所有函数都是以 XYYZZZ 的形式命名
  • 对于某些函数,没有第六个字符,只是 XYYZZ 的形式
  • X 代表数据类型(S D C Z),YY 代表数组的类型,ZZZ代表计算方法

注意:在新版中,使用重复迭代法的函数 DSGESV 和 ZCDESV 头两个字母表示使用的精度

DS 输入双精度,算法使用单精度

ZC 输入使用 DOUBLE COMPLEX,算法使用 COMPLEX 单精度

 

几种常用的数组类型

记号 类型
DI (diagonal) 对角阵
GB (general band) 一般带状矩阵
GE (general) 一般矩阵
GT (general tridiagonal) 一般三对角阵
OR (real orthogonal) 实正交阵
SB (real symmetric) 实对称带状阵
ST (real symmetric tridiagonal) 实对称三对角阵
SY (symmetric) 对称阵
TB (triangularband) 三角形带状矩阵

 

编译指令

使用 gfortran 编译,通过-l导入静态库;导入静态库的顺序不能变

gfortran test.cpp -o test -llapacke -llapack -lblas

注意:此时程序必须使用 C 语言编写

 

  • 链接 C++ 库

通过添加参数来调用 C++ 相关的库和使用新标准

gfortran test.cpp -o test -llapacke -llapack -lblas -lstdc++ -std=c++11 # 链接 C++ 标准库 + C++11 标准

 

  • 链接 fortran 库

如果使用 g++ 进行编译,则需要链接 fortran 库

g++ test.cpp -o test -llapacke -llapack -lblas -lgfortran

另外,需要注意的是,由于高版本的 gcc 默认会在编译参数中添加 -fPIC 参数以实现相对路径的共享,因此可能导致编译时不能正确链接库,这时就需要添加 -no-pie 参数来取消 -fPIC 参数

g++ test.cpp -o test -llapacke -llapack -lblas -lgfortran -no-pie

 

  • 使用 extern 修饰
extern void c_func1(float*, int);  	 // 使用 C++ 的编译修饰规则,Fortran 无法调用
extern "C" int c_func2();            // 使用 C 的编译修饰规则,Fortran 可以调用

 

LAPACK语法

Lapack 函数手册:

http://www.netlib.org/lapack/single/

http://www.netlib.org/lapack/double/

http://www.netlib.org/lapack/complex/

http://www.netlib.org/lapack/complex16

通过 XYYZZZ 中部分类型的组合,我们可以得到不同的函数 LAPACK_XYYZZZ

区分例程

// Linear system, solve Ax = b
LAPACKE_XYYsv(); 	// 标准求解
LAPACKE_XYYsvx(); 	// 精确求解:包括 A'x = b,条件数,误差分析等

// Linear least squares, minimize ||b - Ax||2
LAPACKE_XYYls(); 	// A满秩,QR求解

 

参数格式

// 标准求解 Ax = B A = N x N, B = N x NRHS, X = N x NRHS
lapack_int LAPACKE_dgesv( 
    int matrix_layout, 		 // 矩阵的格式
    lapack_int n,			// 方程组的行数,也即矩阵 A 的行数
    lapack_int nrhs,		// rhs: right-hand-side 右边矩阵的列数,也即 B 的列数
                          
    double* a, 				// 矩阵 A
    lapack_int lda, 		// 数组 A 的主尺寸,这是存放矩阵 A 的数组的尺寸,不小于 N
    lapack_int* ipiv,		// 长为 N 的数组,用于定义置换矩阵 P,一般初始化为0即可
                          
    double* b, 				// 矩阵 B
    lapack_int ldb 			// 数组 B 的主尺寸,这是存放矩阵 B 的数组的尺寸,不小于 N
);
//

matrix_layout

  • LAPACK_ROW_MAJOR 按行求解(标准)
  • LAPACK_COL_MAJOR 按列求解

之后介绍的 Lapack 函数中 matrix_layout 都会沿用这两个宏。

 

LAPACK 函数

degsv

求解一般实线性方程组 \(AX=B\) ,其中 \(A\in\mathbb{R}^{N\times N},\ X,B\in\mathbb{R}^{N\times NRHS}\) ,并且要求 \(A\) 可逆。求解过程使用列主元 \(LU\) 分解法,

\[A = PLU \]

其中 \(P\) 是置换阵, \(L,U\) 分别为上下三角阵。

lapack_int LAPACKE_dgesv( int matrix_layout, lapack_int n, lapack_int nrhs,
                          double* a, lapack_int lda, lapack_int* ipiv,
                          double* b, lapack_int ldb );

参数:

  • N - 线性方程的个数,也就是 \(A\) 的阶数
  • NRHS - 矩阵 \(B\) 的列数
  • A - 矩阵 \(A\) ,返回储存 \(A\) 的 \(LU\) 分解
  • LDA - 数组 \(A\) 的行维数, \(LDA \ge \max(1,N)\)
  • IPIV - 存放返回维数为 \(N\) 的置换向量,行 \(i\) 被替换为行 \(IPIV(i)\)
  • B - 矩阵 \(B\)
  • LDB - 数组 \(B\) 的行维数, \(LDB\ge \max(1,N)\) ,注意是数组 \(B\) ,如果是单列向量,行数是 1

返回 INFO 存放计算标识:

  • 0 成功退出
  • < 0INFO = -i ,则第 \(i\) 个变量是一个不可接受的值
  • > 0INFO = i ,则 \(U(i,i)\) 为零,因式分解完成,但 \(U\) 不可逆

 

dgels

求解超定或欠定实线性方程组,涉及 \(A\in\mathbb{R}^{M\times N}\) 或者它的转置,使用 \(QR\) 或 \(LQ\) 分解,它假定 \(A\) 满秩。

lapack_int LAPACKE_dgels( int matrix_layout, char trans, lapack_int m,
                          lapack_int n, lapack_int nrhs, double* a,
                          lapack_int lda, double* b, lapack_int ldb );

可选参数 TRANS :

  • TRANS = 'N', m>= n :求超定系统 \(\|B-AX\|\) 的最小解
  • TRANS = 'N', m<n :求欠定系统的最小解
  • TRANS = 'T', m>= n :求欠定系统 \(A^TX=B\) 的最小解
  • TRANS = 'T', m<n :求超定系统 \(\|B-A^TX\|\) 的最小解

右边向量 \(b\) 和解向量 \(x\) 分别存放为 \(M\times NRHS\) 矩阵 \(B\) 和 \(N\times NRHS\) 矩阵 \(X\) 。

参数:

  • TRANS - 如上
  • M - 矩阵 \(A\) 的行数
  • N - 矩阵 \(A\) 的列数
  • NRHS - 矩阵 \(B\) 的列数
  • A - 矩阵 \(A\) ,如果 \(M>=N\) ,则 \(A\) 由 \(QR\) 分解覆盖;否则 \(A\) 由 \(LQ\) 分解覆盖
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,M)\)
  • B - 矩阵 \(B\) ,情况比较复杂,只考虑 TRANS = 'N', m>=n ,此时第 1 到 n 行包含最小二乘向量,第 n+1 到 M 行每列的平方和给出残向量 \(B-AX\) 每列的平方和
  • LDB - 数组 \(B\) 的行维数, \(LDB\ge \max(1,M,N)\)

 

dsyev

求解实对称矩阵 \(A\) 的所有特征值和对应的特征向量

lapack_int LAPACKE_dsyev( int matrix_layout, char jobz, char uplo, lapack_int n,
                          double* a, lapack_int lda, double* w );

参数:

  • JOBZ - 若为 'N' ,表示只计算特征值;若为 'V' 表示计算特征值和特征向量
  • UPLO - 若为 'U' ,表示存放 \(A\) 的上三角部分;若为 'L' ,表示存放 \(A\) 的下三角部分
  • N - 矩阵 \(A\) 的阶数
  • A - 矩阵 \(A\) ,如果 UPLO 为 'U' ,则 \(A\) 的前 \(N\times N\) 上三角部分存放在上三角部分(因为没有必要存放整个 \(A\) ),反之同理;如果 JOBZ 为 'V' ,则 \(A\) 存放正交特征向量;否则根据 UPLO 返回 \(A\) 其部分,其它部分会被摧毁
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,N)\)
  • W - 返回维数为 \(N\) 的向量,升序存放特征值

 

dgees

求解实非对称矩阵 \(A\in\mathbb{R}^{n\times n}\) 的特征值,实 Schur 分解,以及 Schur 向量的矩阵,给出 Schur 分解 \(A = ZTZ^T\) ;也可以选择将对角线上的特征值排序,则 \(Z\) 的第一列就是对应特征值子空间的一个正交基。

lapack_int LAPACKE_dgees( int matrix_layout, char jobvs, char sort,
                          LAPACK_D_SELECT2 select, lapack_int n, double* a,
                          lapack_int lda, lapack_int* sdim, double* wr,
                          double* wi, double* vs, lapack_int ldvs );

参数:

  • JOBVS - 若为 'N' ,则不计算 Schur 向量;若为 'V' 则计算
  • SORT - 若为 'N' ,则不对对角特征值排序;若为 'S' 则排序
  • SELECT - 参数过于复杂,当 SORT 为 'N' ,此参数不被引用
  • N - 矩阵 \(A\) 的阶数
  • A - 矩阵 \(A\) ,返回 Schur 标准型
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,N)\)
  • SDIM - 返回值,若 SORT 为 'N' ,返回 0
  • WR - 返回 \(N\) 维数组
  • WI - 返回 \(N\) 维数组,它们分别存放特征值的实部和虚部,共轭特征对会以虚部为正负的顺序连续出现
  • VS - 返回 \(LDVS\times N\) 数组,若 JOBVS 为 'V' ,则其中包含 Schur 向量构成的正交阵 \(Z\) ;否则不被引用
  • LDVS - 数组 VS 的行维数

 

dgecon

计算一般实矩阵 \(A\) 的条件数

lapack_int LAPACKE_dgecon( int matrix_layout, char norm, lapack_int n,
                           const double* a, lapack_int lda, double anorm,
                           double* rcond );

参数:

  • NORM - 若为 '1' 表示 1 范数,为 'I' 表示无穷范数
  • N - 矩阵 \(A\) 的阶数
  • A - 矩阵 \(A\)
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,N)\)
  • ANORM - 初始矩阵的范数
  • RCOND - 返回 RCOND = 1/(norm(A) * norm(inv(A)))

 

dgehrd

通过正交变换 \(Q^TAQ =H\) 将一般实矩阵 \(A\) 化为上 Hessenberg 阵 \(H\) 。

lapack_int LAPACKE_dgehrd( int matrix_layout, lapack_int n, lapack_int ilo,
                           lapack_int ihi, double* a, lapack_int lda,
                           double* tau );

参数:

  • N - 矩阵 \(A\) 的阶数
  • ILO - 输入整型
  • IHI - 输入整型;它们假设矩阵 \(A\) 已经在 1:ILO-1 行列和 IHI+1:N 行列部分上三角化。只有当已经调用了 dgebal 后才会设置它们,否则请将它们分别设为 1 和 N
  • A - 矩阵 \(A\) ,返回上三角和次对角线为上 Hessenberg 化矩阵 \(H\) ,剩下的元素和 TAU 一起存放正交阵 \(Q\)
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,N)\)
  • TAU - 返回 \(N-1\) 维数组,存放变换阵的标量因子,具体解释如下:
/*  Further Details
*  ===============
*
*  The matrix Q is represented as a product of (ihi-ilo) elementary
*  reflectors
*
*     Q = H(ilo) H(ilo+1) . . . H(ihi-1).
*
*  Each H(i) has the form
*
*     H(i) = I - tau * v * v**T
*
*  where tau is a real scalar, and v is a real vector with
*  v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on
*  exit in A(i+2:ihi,i), and tau in TAU(i).
*
*  The contents of A are illustrated by the following example, with
*  n = 7, ilo = 2 and ihi = 6:
*
*  on entry,                        on exit,
*
*  ( a   a   a   a   a   a   a )    (  a   a   h   h   h   h   a )
*  (     a   a   a   a   a   a )    (      a   h   h   h   h   a )
*  (     a   a   a   a   a   a )    (      h   h   h   h   h   h )
*  (     a   a   a   a   a   a )    (      v2  h   h   h   h   h )
*  (     a   a   a   a   a   a )    (      v2  v3  h   h   h   h )
*  (     a   a   a   a   a   a )    (      v2  v3  v4  h   h   h )
*  (                         a )    (                          a )
*
*  where a denotes an element of the original matrix A, h denotes a
*  modified element of the upper Hessenberg matrix H, and vi denotes an
*  element of the vector defining H(i).
*/

 

dgeqrf

计算一个实 \(M\times N\) 矩阵 \(A\) 的 \(QR\) 分解

lapack_int LAPACKE_dgeqrf( int matrix_layout, lapack_int m, lapack_int n,
                           double* a, lapack_int lda, double* tau );

参数:

  • M - 矩阵 \(A\) 的行数
  • N - 矩阵 \(A\) 的列数
  • A - 矩阵 \(A\) ,返回上三角部分为 \(R\) ,其下的部分和 TAU 存放正交阵 \(Q\)
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,M)\)
  • TAU - 返回标量因子 \(\min(M,N)\) 维向量,具体解释如下:
/*  Further Details
*  ===============
*
*  The matrix Q is represented as a product of elementary reflectors
*
*     Q = H(1) H(2) . . . H(k), where k = min(m,n).
*
*  Each H(i) has the form
*
*     H(i) = I - tau * v * v**T
*
*  where tau is a real scalar, and v is a real vector with
*  v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i),
*  and tau in TAU(i).
*/

 

dgetrf

计算一个实 \(M\times N\) 矩阵 \(A\) 的列主元 \(LU\) 分解

lapack_int LAPACKE_dgetrf( int matrix_layout, lapack_int m, lapack_int n,
                           double* a, lapack_int lda, lapack_int* ipiv );

参数:

  • M - 矩阵 \(A\) 的行数
  • N - 矩阵 \(A\) 的列数
  • A - 矩阵 \(A\) ,返回存储 \(L,U\)
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,M)\)
  • IPIV - 返回 \(\min(M,N)\) 维向量,存放置换向量,行 \(i\) 被替换为行 \(IPIV(i)\)

 

dgetri

利用 \(LU\) 分解计算一个矩阵的逆,它先求 \(U\) 的逆,然后求解 \(A^{-1}L = U^{-1}\) 得到 \(A^{-1}\)

lapack_int LAPACKE_dgetri( int matrix_layout, lapack_int n, double* a,
                           lapack_int lda, const lapack_int* ipiv );

参数:

  • N - 矩阵 \(A\) 的阶数
  • A - 矩阵 \(A\) ,
  • LDA - 数组 \(A\) 的行维数, \(LDA\ge\max(1,N)\)
  • IPIV - 存放置换向量的 \(N\) 维数组

 

LAPACK实例

使用标准函数求解线性方程组

利用 LAPACK_dgels求解最小二乘问题

#include <stdio.h>
#include <lapacke.h>
 
int main (int argc, const char * argv[])
{
   double a[5*3] = {1,2,3,4,5,1,3,5,2,4,1,4,2,5,3};
   double b[5*2] = {-10,12,14,16,18,-3,14,12,16,16};
   lapack_int info,m,n,lda,ldb,nrhs;
   int i,j;
 
   m = 5;
   n = 3;
   nrhs = 2;
   lda = 5;
   ldb = 5;
 
   info = LAPACKE_dgels(LAPACK_COL_MAJOR,'N',m,n,nrhs,a,lda,b,ldb);
 
   for(i=0;i<n;i++)
   {
      for(j=0;j<nrhs;j++)
      {
         printf("%lf ",b[i+ldb*j]);
      }
      printf("\n");
   }
   return(info);
}

标签:LDA,lapack,Lapack,科学计算,矩阵,int,数组,double
来源: https://www.cnblogs.com/Bluemultipl/p/15915323.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有