Boost的ublas求矩阵逆

Boost的ublas求矩阵逆

LU Matrix Inversion


The following code inverts the matrix input using LU-decomposition with backsubstitution of unit vectors. Reference: Numerical Recipies in C, 2nd ed., by Press, Teukolsky, Vetterling & Flannery.

 

 #ifndef INVERT_MATRIX_HPP #define INVERT_MATRIX_HPP

 

 // REMEMBER to update "lu.hpp" header includes from boost-CVS #include <boost/numeric/ublas/vector.hpp> #include <boost/numeric/ublas/vector_proxy.hpp> #include <boost/numeric/ublas/matrix.hpp> #include <boost/numeric/ublas/triangular.hpp> #include <boost/numeric/ublas/lu.hpp> #include <boost/numeric/ublas/io.hpp>

 

 namespace ublas = boost::numeric::ublas;

 

 template<class T> bool InvertMatrix? (const ublas::matrix<T>& input, ublas::matrix<T>& inverse) { using namespace boost::numeric::ublas; typedef permutation_matrix<std::size_t> pmatrix; // create a working copy of the input matrix<T> A(input); // create a permutation matrix for the LU-factorization pmatrix pm(A.size1());

 

 // perform LU-factorization int res = lu_factorize(A,pm); if( res != 0 ) return false;

 

 // create identity matrix of "inverse" inverse.assign(ublas::identity_matrix<T>(A.size1()));

 

 // backsubstitute to get the inverse lu_substitute(A, pm, inverse);

 

 return true; }

 

 #endif //INVERT_MATRIX_HPP

Hope someone finds this useful. Regards, Fredrik orderud.

 

Matrix inversion with Singularity Detection

This version is efficient as using LU. A more complex and probably inefficient version is at the second section of Effective UBLAS/Matrix Inversion.

-----------------------------------------

I (Andrey Zakharov,anzakhar@narod.ru) correct the "Another Matrix Inverse implementation" by Yi Wang so:

 

 

 #include <boost/numeric/ublas/matrix.hpp> #include <boost/numeric/ublas/matrix_proxy.hpp> #include <boost/numeric/ublas/io.hpp> #include <boost/numeric/ublas/matrix_expression.hpp>

 

 #include <iostream> #include <fstream> #include <vector>

 

 

 template<class T> //#define T double /// for debug boost::numeric::ublas::matrix<T> gjinverse(const boost::numeric::ublas::matrix<T> &m, bool &singular) { using namespace boost::numeric::ublas;

 

 const int size = m.size1();

 

 // Cannot invert if non-square matrix or 0x0 matrix. // Report it as singular in these cases, and return // a 0x0 matrix. if (size != m.size2() || size == 0) { singular = true; matrix<T> A(0,0); return A; }

 

 // Handle 1x1 matrix edge case as general purpose // inverter below requires 2x2 to function properly. if (size == 1) { matrix<T> A(1, 1); if (m(0,0) == 0.0) { singular = true; return A; } singular = false; A(0,0) = 1/m(0,0); return A; }

 

 // Create an augmented matrix A to invert. Assign the // matrix to be inverted to the left hand side and an // identity matrix to the right hand side. matrix<T> A(size, 2*size); matrix_range<matrix<T> > Aleft(A, range(0, size), range(0, size)); Aleft = m; matrix_range<matrix<T> > Aright(A, range(0, size), range(size, 2*size)); Aright = identity_matrix<T>(size);

 

 / // INCORRECT PLACEMENT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // // Swap rows to eliminate zero diagonal elements. // for (int k = 0; k < size; k++) // { // if ( A(k,k) == 0 ) // XXX: test for "small" instead // { // // Find a row(l) to swap with row(k) // int l = -1; // for (int i = k+1; i < size; i++) // { // if ( A(i,k) != 0 ) // { // l = i; // break; // } // } // // // Swap the rows if found // if ( l < 0 ) // { // std::cerr << "Error:" << __FUNCTION__ << ":" // << "Input matrix is singular, because cannot find" // << " a row to swap while eliminating zero-diagonal."; // singular = true; // return Aleft; // } // else // { // matrix_row<matrix<T> > rowk(A, k); // matrix_row<matrix<T> > rowl(A, l); // rowk.swap(rowl); // // #if defined(DEBUG) || !defined(NDEBUG) // std::cerr << __FUNCTION__ << ":" // << "Swapped row " << k << " with row " << l // << ":" << A << "\n"; // #endif // } // } // } // /

 

 // Doing partial pivot for (int k = 0; k < size; k++) { /// // RIGHT PLACEMENT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

 // Swap rows to eliminate zero diagonal elements. for (int k = 0; k < size; k++) { if ( A(k,k) == 0 ) // XXX: test for "small" instead { // Find a row(l) to swap with row(k) int l = -1; for (int i = k+1; i < size; i++) { if ( A(i,k) != 0 ) { l = i; break; } }

 

 // Swap the rows if found if ( l < 0 ) { std::cerr << "Error:" << __FUNCTION__ << ":" << "Input matrix is singular, because cannot find" << " a row to swap while eliminating zero-diagonal."; singular = true; return Aleft; } else { matrix_row<matrix<T> > rowk(A, k); matrix_row<matrix<T> > rowl(A, l); rowk.swap(rowl);

 

 #if defined(DEBUG) || !defined(NDEBUG) std::cerr << __FUNCTION__ << ":" << "Swapped row " << k << " with row " << l << ":" << A << "\n"; #endif } } }

 

 / // normalize the current row for (int j = k+1; j < 2*size; j++) A(k,j) /= A(k,k); A(k,k) = 1;

 

 // normalize other rows for (int i = 0; i < size; i++) { if ( i != k ) // other rows // FIX: PROBLEM HERE { if ( A(i,k) != 0 ) { for (int j = k+1; j < 2*size; j++) A(i,j) -= A(k,j) * A(i,k); A(i,k) = 0; } } }

 

 #if defined(DEBUG) || !defined(NDEBUG) std::cerr << __FUNCTION__ << ":" << "GJ row " << k << " : " << A << "\n"; #endif }

 

 singular = false; return Aright; }

Warning!!!!! Compiling your code with

gcc version 3.4.6 20060404 (Red Hat 3.4.6-3)

Gives me these warning:

./mysource.cpp:232: warning: name lookup of `k' changed ./mysource.cpp:191: warning: matches this `k' under ISO standard rules ./mysource.cpp:197: warning: matches this `k' under old rules

Line 232: for (int j = k+1; j < 2*size; j++)

Line 190: // Doing partial pivot Line 191: for (int k = 0; k < size; k++)

Line 196: // Swap rows to eliminate zero diagonal elements. Line 197: for (int k = 0; k < size; k++)

So, what k are you using at line 232? the one at 191 or the one at 197? Can you change your variables??

 

 

A Matrix Inverse implementation using QR decomposition

I (Eustache Diemert, eustache_at_diemert_dot_fr), gives this example code to compute square matrix inverse using QR decomposition (more precisely Householder reflections). Here it is:

 

 

 template<class T> void TransposeMultiply? (const ublas::vector<T>& vector, ublas::matrix<T>& result, size_t size) { result.resize (size,size); result.clear (); for(unsigned int row=0; row< vector.size(); ++row) { for(unsigned int col=0; col < vector.size(); ++col) result(row,col) = vector(col) * vector(row);

 

 } }

 

 template<class T> void HouseholderCornerSubstraction? (ublas::matrix<T>& LeftLarge?, const ublas::matrix<T>& RightSmall?) { using namespace boost::numeric::ublas; using namespace std; if( !( (LeftLarge?.size1() >= RightSmall?.size1()) && (LeftLarge?.size2() >= RightSmall?.size2()) ) ) { cerr << "invalid matrix dimensions" << endl; return; }

 

 size_t row_offset = LeftLarge?.size2() - RightSmall?.size2(); size_t col_offset = LeftLarge?.size1() - RightSmall?.size1();

 

 for(unsigned int row = 0; row < RightSmall?.size2(); ++row ) for(unsigned int col = 0; col < RightSmall?.size1(); ++col ) LeftLarge?(col_offset+col,row_offset+row) -= RightSmall?(col,row); }

 

 template<class T> void HouseholderQR? (const ublas::matrix<T>& M, ublas::matrix<T>& Q, ublas::matrix<T>& R) { using namespace boost::numeric::ublas; using namespace std;

 

 if( !( (M.size1() == M.size2()) ) ) { cerr << "invalid matrix dimensions" << endl; return; } size_t size = M.size1();

 

 // init Matrices matrix<T> H, HTemp; HTemp = identity_matrix<T>(size); Q = identity_matrix<T>(size); R = M;

 

 // find Householder reflection matrices for(unsigned int col = 0; col < size-1; ++col) { // create X vector ublas::vector<T> RRowView? = column(R,col); vector_range< ublas::vector<T> > X2 (RRowView?, range (col, size)); ublas::vector<T> X = X2;

 

 // X -> U~ if(X(0) >= 0) X(0) += norm_2(X); else X(0) += -1*norm_2(X);

 

 HTemp.resize(X.size(),X.size(),true);

 

 TransposeMultiply?(X, HTemp, X.size());

 

 // HTemp = the 2UUt part of H HTemp *= ( 2 / inner_prod(X,X) );

 

 // H = I - 2UUt H = identity_matrix<T>(size); HouseholderCornerSubstraction?(H,HTemp);

 

 // add H to Q and R Q = prod(Q,H); R = prod(H,R); } }

And a dummy main() to test it :

 

 int main() { using namespace boost::numeric::ublas; using namespace std; matrix<double> A (3,3); A(0,0) = 1; A(0,1) = 1; A(0,2) = 0; A(1,1) = 1; A(1,0) = 0; A(1,2) = 0; A(2,2) = 1; A(2,0) = 1; A(2,1) = 0; cout << "A=" << A << endl;

 

 cout << "QR decomposition using Householder" << endl; matrix<double> Q(3,3), R(3,3); HouseholderQR? (A,Q,R); matrix<double> Z = prod(Q,R) - A; float f = norm_1 (Z); cout << "Q=" << Q <<endl; cout << "R=" << R << endl; cout << "|Q*R - A|=" << f << endl;

 

 return 0; }

f value should be approximately 4e-16.

-------------------------

[Home]Linear Algebra With UBLAS

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
 


Linear Algebra with uBLAS

Effective uBLAS

uBLAS is, more or less, BLAS (see http://www.netlib.org/blas/). It provides the "building blocks" for storing vector and matricies and vector and matrix operations (scaling, addition, multiplication etc). uBLAS provides the C++ infrastructure on which safe and efficient linear algebra algorithms can be built.

 

Solve and Factorisation in uBLAS

uBLAS has solve() functions [1], corresponding to the BLAS trsm() functions. These functions are `triangular' solvers. Triangular matrices have a trivial inverse, and therefore their solution is defined a BLAS function. The solve() function can by used for `backward' substitutions after LU or Cholesky factorisations.

uBLAS also has a set of functions for LU factorisation. These implement common LU factorisation algorithms directly in uBLAS. They are defined in the header file <boost/numeric/ublas/lu.hpp>. LU Matrix Inversion demonstrates how these functions can be used to invert matrices.

 

Interfacing with other Libraries

Linear Algebra is huge topic. There are many thousands of algorithms. Since the 70s large scale libraries of peer-reviewed algorithms have been assembled. These were usually written in Fortran. The most well know are LINPACK and LAPACK (see http://www.netlib.org ). More recently ATLAS has been developed. This has C and Fortran interfaces and includes both reimplemented BLAS functions as well as some important LAPACK algorithms.

 

Bindings

The best way to interface with these libraries is to use a `bindings' library which *can be used with uBLAS vectors and matrices*. Kresimir Fresl is continuously developing and updating such a library.

For example, for matrix inversion using an LU factorisation you can use ATLAS bindings:

 

 #include <boost/numeric/bindings/atlas/clapack.hpp> #include <boost/numeric/bindings/traits/ublas_matrix.hpp> #include <boost/numeric/bindings/traits/std_vector.hpp>

 

 namespace ublas = boost::numeric::ublas; namespace atlas = boost::numeric::bindings::atlas;

 

 int main() { std::size_t n = 5; ublas::matrix<double> A (n, n); // fill matrix A

 

 std::vector<int> ipiv (n); // pivot vector atlas::lu_factor (A, ipiv); // alias for getrf() atlas::lu_invert (A, ipiv); // alias for getri() }

 

Of course, you must install ATLAS first:

 

 http://math-atlas.sourceforge.net/ 

"The ATLAS (Automatically Tuned Linear Algebra Software) project is an ongoing research effort focusing on applying empirical techniques in order to provide portable performance. At present, it provides C and Fortran77 interfaces to a portably efficient BLAS implementation, as well as a few routines from LAPACK."

The `bindings' library is a very useful interface between Boost and uBLAS and traditional linear algebra libraries. It is being actively maintianed with the hope of eventual inclusion in Boost.

Development of the binding interface is located at Boost Sandbox CVS - http://www.boost.org/more/mailing_lists.htm#sandbox

Here you can also find newest, sometimes experimental,versions of the binding. You can access the header files directly at:

http://boost-sandbox.cvs.sourceforge.net/boost-sandbox/boost-sandbox/boost/numeric/bindings/

The starting point for documentation and the many examples is:

 

 boost-sandbox/boost-sandbox/libs/numeric/bindings

Examples for matrix inversion with ATLAS are in `atlas/ublas_getri.cc' and,if your matrix is SPD, in `atlas/ublas_potri.cc'.

You may also download ready-made snapshot releases of the bindings from http://news.tiker.net/software/boost-bindings.

 

What about using LAPACK++?

From the LAPACK++ home page:

 

 NOTE: This package is being superseded by the Template Numerical Toolkit (TNT), which utilizes new features of the ANSI C++ specification. TNT is a newer design, and will integrate the functionlaity of Lapack++, IML++, SparseLib?++, and MV++. (TNT home page is: http://math.nist.gov/tnt/)

On the other hand, from the homepage of LAPACK++ v2.1.2: http://lapackpp.sourceforge.net/

 However, they abandoned LAPACK in the year 2000 and stated: "Lapack++ is no longer actively supported. The successor to this project is that Template Numerical Toolkit (TNT), see http://math.nist.gov/tnt for details." Unfortunately, the project TNT never really took off. Therefore this fork from the original LAPACK++ has been started. There are a whole number of changes now in here. Most notably, this local copy has complex matrices enabled again by adding a custom copy of stdc++'s complex type (see include/lacomplex.h and include/lacomplex).

So my question, again: What about LAPACK++ ?

Blaisorblade(not a Boost developer) answers (there are updates from the first answer):

LAPACK++ seems fairly complete (and its API seems a lot more reasonable than the API of bindings to LINPACK), but it seems not written by C++ experts. Beyond that, it contains its own reimplementation of basic vector operation (indeed, its own reimplementation of BLAS for C++), but it is a really inferior one (it does not definitely use expression templates).

Say, in LAPACK++ 2.5.2, LaGenMatDouble? class (a double dense matrix) has two identical methods, having these signatures:

 

 LaGenMatDouble? operator()(const LaIndex?& I, const LaIndex?& J); LaGenMatDouble? operator()(const LaIndex?& I, const LaIndex?& J) const;

the non-const overload returns a copy of the selected portion of the matrix, not a view I wonder if they understand that the second overload is not needed. EDIT: things are worse; _both_ operators return a _modifiable_ view, and what's worse is that constness is never enforced. The following code snippet compiles:

 

 const LaGenMatDouble? A = LaGenMatDouble?::rand(3, 3); A(0, 0) = 1;

In the overload of operator() to access a single element (operator()(int row, int column)), a reference to the element is returned; I wonder whether they'd need to return a proxy reference, since they can share the backing array.

EDIT: additionally, the LAPACK++ developers do not know about thread safety, and they ignore the very existence of mutable. Look at this comment from source code:

 

 static int *info_; // print matrix info only, not values // originally 0, set to 1, and then // reset to 0 after use. // use as in // // std::cout << B.info() << std::endl; // // this *info_ member is unique in that it really isn't // part of the matrix info, just a flag as to how // to print it. We've included in this beta release // as part of our testing, but we do not expect it // to be user accessable. // It has to be declared as global static // so that we may monitor expresssions like // X::(const &X) and still utilize without violating // the "const" condition. // Because this *info_ is used at most one at a time, // there is no harm in keeping only one copy of it, // also, we do not need to malloc free space every time // we call a matrix constructor. 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值