CBLAS
是
BLAS
的
C
语言接口。
BLAS
的全称是
Basic Linear Algebra Subprograms
,中文大概可以叫做基础线性代数子程序。主要是用于向量和矩阵计算的高性能数学库。本身
BLAS
是用
Fortran
写的,为了方便
C/C++
程序的使用,就有了
BLAS
的
C
接口库
CBLAS
。
BLAS
的主页是
http://www.netlib.org/blas/
,
CBLAS
的下载地址也可以在这个页面上找到。
CBLAS
安装需要先装
BLAS
,从主页上下载
blas.tgz
,解压,根据系统修改
make.inc
和
Makefile
,
make
,就会生成一个
blas_LINUX.a
文件。然后,下载
cblas.tgz
,解压,在目录下将
Makefile.*
文件改名或者做一个链接文件为
Makefile.in
文件,比如在
linux
下就是
ln -s Makefile.LINUX Makefile.in
,根据具体情况修改
Makefile.in
文件,主要是
BLAS
的库文件路径
BLLIB
和
CBLAS
的安装目录
CBDIR
,
make help
就可以打印出可以使用的
make
命令,要生成全部文件就是用
make all
。在
$(CBDIR)
目录下的
$(CBLIBDIR)
将生成
CBLAS
的库文件
$(CBLIB)
,
cblas_LINUX.a
。
在
CBLAS
的安装目录
$(CBDIR)
下的
src
目录中有个
cblas.h
是包括的
CBLAS
的函数和常量的头文件,使用
CBLAS
的时候就需要这个头文件,同时还需要
BLAS
的库文件
$(BLLIB )
和
CBLAS
的库文件
$(CBLIB)
。
CBLAS/BLAS
分为
3
个
level
,
level1
是用于向量的计算,
level2
是用于向量和矩阵之间的计算,
level3
是矩阵之间的计算。比如计算矩阵的乘法就是属于
level3
,这里就用矩阵乘法来学习使用
CBLAS
。
计算矩阵乘法的函数之一是
cblas_sgemm
,使用单精度实数,另外还有对应双精度实数,单精度复数和双精度复数的函数。在此以
cblas_sgemm
为例。
函数定义为:
void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
const int K, const float alpha, const float *A,
const int lda, const float *B, const int ldb,
const float beta, float *C, const int ldc)
关于此
函数的
详细定义可以在
http://www.netlib.org/blas/sgemm.f
找到,只不过是
fortran
语言的
,
这个
C
语言版的略有差别。
此函数计算的是
C = alpha*op( A )*op( B ) + beta*C,
const enum CBLAS_ORDER Order
,这是指的数据的存储形式,在
CBLAS
的函数中无论一维还是二维数据都是用一维数组存储,这就要涉及是行主序还是列主序,在
C
语言中数组是用行主序,
fortran
中是列主序。我还是习惯于是用行主序,所以这个参数是用
CblasRowMajor
,如果是列主序的话就是
CblasColMajor
。
const enum CBLAS_TRANSPOSE TransA
和
const enum CBLAS_TRANSPOSE TransB
,这两个参数影响的是
op( A )
和
op( B)
,可选参数为
CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113
,其中
TransA = CblasNoTrans, op( A ) = A
,
TransA = CblasTrans, op( A ) = A'
,
TransA = CblasConjTrans, op( A ) = A'
。
TransB
类似。
const int M
,矩阵
A
的行,矩阵
C
的行
const int N
,矩阵
B
的列,矩阵
C
的列
const int K
,矩阵
A
的列,矩阵
B
的行
const float alpha
,
const float beta
,计算公式中的两个参数值,如果只是计算
C=A*B
,则
alpha=1,beta=0
const float *A
,
const float *B
,
const float *C
,矩阵
ABC
的数据
const int lda, const int ldb, const int ldc,在BLAS的文档里,这三个参数分别为ABC的行数,但是实际使用发现,在CBLAS里应该是列数。
我在这里计算两个简单矩阵的乘法。
A:
1,2,3
4,5,6
7,8,9
8,7,6
B:
5,4
3,2
1,0
程序代码:
//
因为程序是
C++
,而
CBLAS
是
C
语言写的,所以在此处用
extern
关键字
extern
"C"
{
#include
<cblas.h>
}
#include
<iostream>
using namespace
std;
int
main(
void
) {
const enum
CBLAS_ORDER Order=CblasRowMajor;
const enum
CBLAS_TRANSPOSE TransA=CblasNoTrans;
const enum
CBLAS_TRANSPOSE TransB=CblasNoTrans;
const int
M=4;
//A
的行数,
C
的行数
const int
N=2;
//B
的列数,
C
的列数
const int
K=3;
//A
的列数,
B
的行数
const float
alpha=1;
const float
beta=0;
const int
lda=K;
//A
的列
const int
ldb=N;
//B
的列
const int
ldc=N;
//C
的列
const float
A[K*M]={1,2,3,4,5,6,7,8,9,8,7,6};
const float
B[K*N]={5,4,3,2,1,0};
float
C[M*N];
cblas_sgemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
for
(
int
i=0;i<M;i++)
{
for
(
int
j=0;j<N;j++)
{
cout<<C[i*N+j]<<
"/t"
;
}
cout<<
endl
;
}
return
EXIT_SUCCESS;
}
在编译的时候需要带上
cblas_LINUX.a
和
blas_LINUX.a
,比如,
g++ main.cpp cblas_LINUX.a blas_LINUX.a -o main
当然,这里假定是这两个
.a
文件是放在可以直接访问的位置,或者写全路径也可以。
这种做法在
CentOS.5
下顺利通过,但是在我的
Ubuntu.7.10
下出了问题,
blas_LINUX.a
正常编译生成,但在链接的时候出了错误,所以只好从源里安装了
atlas
,
sudo apt-get install atlas3-base
,在
/usr/lib/atlas/
目录下就会有
libblas.*
和
liblapack.*
库文件,只需要在链接的时候用这里的
blas
库文件替换上文安装的
BLAS
就可以正常编译通过。
另外,在
GSL
下也有
BLAS
和
CBLAS
,在
boost
里有
ublas
也提供
CBLAS/BLAS
的功能,有时间也拿来研究研究。
另附GNU上的一个例子:
The following program computes the product of two matrices using the Level-3 BLAS function SGEMM,
[ 0.11 0.12 0.13 ] [ 1011 1012 ] [ 367.76 368.12 ]
[ 0.21 0.22 0.23 ] [ 1021 1022 ] = [ 674.06 674.72 ]
[ 1031 1032 ]
The matrices are stored in row major order but could be stored in column major order if the first argument of the call to cblas_sgemm was changed to CblasColMajor.
#include <stdio.h>
#include <gsl/gsl_cblas.h>
int
main (void)
{
int lda = 3;
float A[] = { 0.11, 0.12, 0.13,
0.21, 0.22, 0.23 };
int ldb = 2;
float B[] = { 1011, 1012,
1021, 1022,
1031, 1032 };
int ldc = 2;
float C[] = { 0.00, 0.00,
0.00, 0.00 };
/* Compute C = A B */
cblas_sgemm (CblasRowMajor,
CblasNoTrans, CblasNoTrans, 2, 2, 3,
1.0, A, lda, B, ldb, 0.0, C, ldc);
printf ("[ %g, %g\n", C[0], C[1]);
printf (" %g, %g ]\n", C[2], C[3]);
return 0;
}
To compile the program use the following command line,
$ gcc -Wall demo.c -lgslcblas
There is no need to link with the main library -lgsl in this case as the CBLAS library is an independent unit. Here is the output from the program,
$ ./a.out
[ 367.76, 368.12
674.06, 674.72 ]