因为看C++数值算法(实际名字是,第二版的Fortran,C,Matlab版本都存在),本书最后部分给出的基本数据类型的头文件中,有一种做法是基 于TNT实现.遂在网上查了一下这个TNT是什么东西.发现实际上是一个实现线性代数底层存储的小型模板库.TNT的全称是”Template Numerical Toolkit”,缩写刚好和黄色炸药的一样,不知道是刚好这样还是创始者的恶趣味.
下载之后发现这个库的代码量很小,只有区区二十来个文件,所以顺便完整的把代码看了一遍,想着之前没有用C++写过大规模的代码,完全不知道用C++写成体系的代码是个什么体验,这次算是学习一下.
废话结束,官方网站上给出的库实际上由两个部分组成.第一部分是TNT,定义了一二三维的数组对象模板,和在这些模板上的基础运算,像矩阵加减,矩阵乘之类的.另一个是JAMA,基于TNT之上的线性算法库,实现一些经典的矩阵算法,如LU,QR,SVD分解之类.本文只记录TNT的具体实现.
TNT包含的具体文件如下,每个类或函数,如无特殊说明,都在TNT名字空间里,每个文件给出相应的功能注释:
tnt_version.h
定义了关于软件版本信息的几个宏,其实没有什么用,相应的几个宏都在全局空间.
tnt_subscript.h
定义了一个下标类型:Subscript
实际上默认类型就是int
,声明这么一个类型是为方便将来需要使用非常大型的数据时能很方便的重新定义吧.但实际上,申请比int最大值更大的内存空间,就现在的眼光看来,几乎是无法想象的事.
tnt_stopwatch.h
定义了一个计时器类:Stopwatch
,可以用来计算某段代码运行的时间,有start
,stop
,read
等方法.这个类主要给使用者使用,库的其余部分并没有用到这个类.
tnt_math_utils.h
定义了一个函数模板:hypot
,用来计算三角形的斜边边长,使用的公式是:$$|a|\cdot\sqrt{1+{\left(\frac{b}{a}\right)}^2}$$两个直角边长度参数可正可负,这个函数在库的其余部分没有使用,应该是作为对标准数学函数的一个补充.
tnt_i_refvec.h
定义了一个模板类:i_refvec
,类似智能指针,用来指向一个数组.这个数组可以被多次引用,内部有计数机制,专门申请了一个int
变量存储引用的次数,当引用次数为0时,会释放指向的数组.但i_refvec
本身并不记录数组的长度.TNT定义的各种数组,内部几乎都是用i_refvec
存储原始代数数据.这个类应该主要用来构建TNT的各种数组类,而不是给用户使用.当然用户如果想要把它当做智能指针来用也可以.C++11
标准库里已经给出智能指针的实现.
tnt_vec.h
#include "tnt_subscript.h"
.定义了一个模板类:Vector
,类似vector
,但底层数据只能存储在连续空间,一旦newsize
原来的数据就会被摧毁.相应的,不支持push_back
之类的方法.其实就是一个封装的一维数组,尽量提高效率.本头文件还提供针对Vector
的几个常用运算函数>>,<<,+,-,*,dot_prod(sum(a*b)
.
tnt_cmat.h
#include "tnt_subscript.h"
,#include "tnt_vec.h"
定义了一个模板类Matrix
,直接用一维数组做内部数据存储,应该是为了尽可能提高效率,引用tnt_vector.h
只是为了定义和Vector
相关的运算,不是用来存储数据.用Subscript
做下标函数参数,Matrix,Vector
默认都是深拷贝,除这两个外,其他的数组类默认都是浅拷贝,想要获得独立对象,只能使用copy
函数.tnt_cmat.h
还定义了和矩阵类相关的常用操作,包括:<<,>>,+,-,mult_element(对应元素直接相乘),transpose(转置),matmult(矩阵乘),*(矩阵乘),matmult(和Vector做矩阵乘),*(和Vector做矩阵乘)
似乎Vector
和Matrix
可以算作一个系列,用来做向量和矩阵运算.
tnt_array1d.h
#include "tnt_i_refvec.h"
定义了一个模板类:Array1D
,内部使用i_refvec存储数据.常规的拷贝都是浅拷贝.(注:函数subarray可能存在错误)
[code lang=”cpp” gutter=”false”]if ((i0 > 0) && (i1 < n_) || (i0 <= i1))[/code]
这个函数用来获得一个子向量,当然还是浅拷贝.i0
和i1
是子向量的左右下标,上面的代码用来判断下标是否合法,不合法返回空向量.很明显,合理的代码应该是:
[code lang=”cpp” gutter=”false”]if ((i0 > 0) && (i1 < n_) && (i0 <= i1))[/code]
这个问题在其他的数组模板类的subarray
函数中同样存在.
tnt_array1d_utils.h
Array1D
的伙伴文件,提供对Array1D
的各种操作.包括:<<,>>,+-*/,+=-=*=/=
tnt_array2d.h
#include "tnt_array1d.h"
定义了一个模板类:Array2D
内部使用Array1D
存储数据,Array1D<T*>
存储第一维不同下标指向的地址,大致和Array1D
差不多.
tnt_array2d_utils.h
Array2D
的伙伴头文件,提供对Array2D
的各种操作,包括:<<,>>,+-*/,+=-=*=/=,matmult(矩阵乘)
tnt_array3d.h
#include "array1d.h"
,#include "array2d.h"
定义了模板类Array3D
内部使用Array1D
存储数据,Array2D<T*>
存储一二维下标对应的地址.大致和Array1D差不多.
tnt_array3d_utils.h
Array3D
的伙伴头文件,提供对Array3D
的各种操作,包括:<<,>>,+-*/,+=-=*=/=
tnt_sparse_matrix_csr.h
#include "tnt_array1d.h "
定义了稀疏矩阵类:Sparse_Matrix_CompRow
似乎很不完善,没仔细看.
其他的还有:tnt_fortran_array1d.h
,tnt_fortran_array2d.h
,tnt_fortran_array3d.h
和相应的伙伴头文件.分别定义了模板类:Fortran_Array1D
,Fortran_Array2D
,Fortran_Array3D
.没看出和另外三个有什么大区别.不同处包括非Fortran
有两套下标引用方式,一套是0作为下标开始,另一套1作开始,而Fortran
版本的只有从1开始
Visits: 1602