Thursday, February 12, 2009

 

Some notes on Computation Library - 1

1.
from http://cmsir.scinese.com/2008/02/22/using-lapack-in-c/

Using LAPACK in C/C++

Fortran是科学计算的标准语言,无论是性能,库,还是普及程度都勿庸置疑地是老大。作为最古老的计算机语言,这么多年的积累让其它语言几乎没可能改变这一局面。可惜我在大学时只学了C,这得怪我们系里的课程安排……无奈之下,很多时候只能C + Fortran Library来干活。最常用的Fortran库无疑是Lapack,主要就是各种对角化。这篇文章里就把C/C++中调用Lapack的每一个细节都记录下来,主要目的是让我下次编程时可以不用重复回忆(我已经吃过一次亏了,花了一晚上时间来研究怎么在C/C++里面链接dll这种白痴问题)。如果有朋友也碰到类似的问题,而又碰巧看到了这篇文章(这是小概率事件,google虽然触角无数,但也难以伸到我这网络深处的小地方),也许可以帮你少走些弯路。

言归正传。首先我们假设工作的平台是Windows(bs我吧……)。C++编译器我只对Microsoft Visual C++ 8.0(即Visual Studio 2005)和MinGW gcc/g++比较熟悉,所以也就只包括这两种。如果你想从源码编译Lapack,那么还得有一个Fortran编译器(如果是这样,建议直接用Fortran)。对于大部分懒人,从网上直接Down一个编译好的库就可以了。例如去下面这个网页:

LAPACK & BLAS precompiled binaries for Win32 platform

http://www.fi.muni.cz/~xsvobod2/misc/lapack/

注意下载shared version,static version需要Intel Fortran 9.0的一些库支持。此外,别忘了下载底下的头文件。按照C的惯例,把库文件解压到lib目录,头文件到include目录。库当中除了lapack_win32.dll还有一个叫blas_win32.dll的东西,包括Lapack需要的一些函数,就我们的目的而言,直接无视它就可以。

在开始进入如何编译链接这种糙活之前,先简单介绍几个最常用的矩阵对角化库函数。就我个人而言,要对角化的几乎都是Hermitian矩阵,或者是实对称矩阵。前者一般zheev函数足够解决问题,后者通常是dsyev。在include目录下都有相应名字的头文件。遗憾的是,这些函数的声明都相当吓人,动辄十来个参数,一个一个对着是看什么意思都能把人累死。所以地球上就有好心人做了wrap,在声明上再加一层接口,大大简化了我们的使用。比如

LAPACK/ARPACK Header Files

http://www-heller.harvard.edu/people/shaw/programs/lapack.html

由于是跨语言调用,虽然我们使用的是二进制级的代码,但仍然需要注意C/C++和Fortran底层的一些差别。第一点区别是数据类型。简单地说,C/C++中的单精度浮点数float类型相当于Fortran的real,double相当于doublereal。而Fortran中的complex和doublecomplex则可以用C++标准库中的std::complex及std::complex代替。C里面需要我们自己定义一个struct:

typedef struct {
double r, i;
}doublecomplex;
除了数据类型的转换,最主要的一点是二维数组在内存中的布局:C/C++是按行存放的,而Fortran是按列存放的。对于实对称矩阵或者Hermitian矩阵,问题倒也不大。一般来说只要在把C/C++数组传入Lapack函数前做一个转换即可。

写完了程序,我们可以开始编译了。为了让编译器能找到头文件,需要在选项中添加头文件的搜索目录。对Visual C++,相应的命令行选项是/I。例如说Lapack的头文件都在C:\LAPACK\include,那么就必须在微软的C++编译器cl调用时加上命令行参数 /I “C:\LAPACK\include”。由于IDE的发达,用VC++干活的人几乎不可能直接面对命令行;在Visual Studio里面,打开工程属性对话框,在配置属性->C/C++->常规->附加包含目录中设置一下即可。对于gcc,命令行参数是-IC:\LAPACK\include。

下面的问题是如何在C程序中链接dll。如果你用的是MinGW,恭喜你,这个问题几乎不成为一个问题:只要在最后链接时命令行里添上dll文件名(下面会有一个完整的例子)。如果是Visual C++,事情要复杂一些。光一个dll文件Visual C++还链接不动,你还得有一个lib文件来告诉它dll中都导出(export)了哪些函数。还有一个选择是在代码里面用LoadLibrary这个API动态加载。当然,无论如何微软在这件事上都做得比较煞笔,但是我们没有办法,只好照办之。注意,刚才下载的压缩包中已经包含了相应的lib文件了,但是我自己用下来发现里面的lapack_win32.lib有些问题。没有办法,我们只好DIY到底,自己generate一个。从dll生成lib网上这类工具很多,如果你偷懒也可以直接我自己做的。做好了lib以后,先在工程属性对话框->配置属性->链接器->常规->附加库目录里设置一下你的dll和lib的所在地(正常人会把它们放在一块)。然后配置属性->链接器->输入->附加依赖项中把要链接的Lib文件名写上(这里就是lapack.lib)。这些都设置好了,如果你的程序没有问题,编译应该能够通过了。



<< Home

This page is powered by Blogger. Isn't yours?