226 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
| /*
 | |
|  * SPQRUtil.cpp
 | |
|  *
 | |
|  *   Created on: Jul 1, 2010
 | |
|  *       Author: nikai
 | |
|  *  Description: the utility functions for SPQR
 | |
|  */
 | |
| 
 | |
| #include <gtsam/base/timing.h>
 | |
| #include <gtsam/base/SPQRUtil.h>
 | |
| #include <boost/numeric/ublas/matrix.hpp>
 | |
| #include <boost/numeric/ublas/matrix_proxy.hpp>
 | |
| #include <boost/numeric/ublas/triangular.hpp>
 | |
| 
 | |
| using namespace std;
 | |
| namespace ublas = boost::numeric::ublas;
 | |
| 
 | |
| #ifdef GT_USE_LAPACK
 | |
| namespace gtsam {
 | |
| 
 | |
| 	/* ************************************************************************* */
 | |
| 	long* MakeStairs(Matrix& A) {
 | |
| 
 | |
| 		const long m = A.size1();
 | |
| 		const long n = A.size2();
 | |
| 		long* Stair = new long[n];
 | |
| 
 | |
| 		// record the starting pointer of each row
 | |
| 		double* a[m];
 | |
| 		list<int> remained;
 | |
| 		a[0] = A.data().begin();
 | |
| 		for(int i=0; i<m-1; i++) {
 | |
| 			a[i+1] = a[i] + n;
 | |
| 			remained.push_back(i);
 | |
| 		}
 | |
| 		remained.push_back(m-1);
 | |
| 
 | |
| 		// reorder the rows
 | |
| 		int j;
 | |
| 		vector<int> sorted;
 | |
| 		list<int>::iterator itRemained;
 | |
| 		for(j = 0; j < n; ) {
 | |
| 			// remove the non-zero rows in the current column
 | |
| 			for(itRemained = remained.begin(); itRemained!=remained.end(); ) {
 | |
| 				if (*(a[*itRemained]) != 0) {
 | |
| 					sorted.push_back(*itRemained);
 | |
| 					itRemained = remained.erase(itRemained);
 | |
| 				} else {
 | |
| 					a[*itRemained]++;
 | |
| 					itRemained ++;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			// record the stair number
 | |
| 			Stair[j++] = m - remained.size();
 | |
| 
 | |
| 			if(remained.empty()) break;
 | |
| 		}
 | |
| 
 | |
| 		// all the remained columns have maximum stair
 | |
| 		for (; j<n; j++)
 | |
| 			Stair[j] = m;
 | |
| 
 | |
| 		// copy the new row
 | |
| 		Matrix A_new = zeros(m,n);
 | |
| 		int offset[m];
 | |
| 		offset[0] = 0;
 | |
| 		for(int i=1; i<m; i++)
 | |
| 			offset[i] = offset[i-1] +n;
 | |
| 		vector<int>::const_iterator itSorted;
 | |
| 		double* ptr1 = A.data().begin();
 | |
| 		double* ptr2 = A_new.data().begin();
 | |
| 		int row = 0, sizeOfRow = n * sizeof(double);
 | |
| 		for(itSorted=sorted.begin(); itSorted!=sorted.end(); itSorted++, row++)
 | |
| 			memcpy(ptr2+offset[row], ptr1+offset[*itSorted], sizeOfRow);
 | |
| 
 | |
| 		A = A_new;
 | |
| 
 | |
| 		return Stair;
 | |
| 	}
 | |
| 
 | |
| 	void printColumnMajor(const double* a, const long m, const long n) {
 | |
| 		for(int i=0; i<m; i++) {
 | |
| 			for(int j=0; j<n; j++)
 | |
| 				cout << a[j*m+i] << "\t";
 | |
| 			cout << endl;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* ************************************************************************* */
 | |
| 	void householder_spqr(Matrix &A, long* Stair) {
 | |
| 
 | |
| 	  tic("householder_spqr");
 | |
| 
 | |
| 		long m = A.size1();
 | |
| 		long n = A.size2();
 | |
| 
 | |
| 		bool allocedStair = false;
 | |
| 		if (Stair == NULL) {
 | |
| 		  allocedStair = true;
 | |
| 			Stair = new long[n];
 | |
| 			for(int j=0; j<n; j++)
 | |
| 				Stair[j] = m;
 | |
| 		}
 | |
| 
 | |
| 		tic("householder_spqr: row->col");
 | |
| 		// convert from row major to column major
 | |
| 		ublas::matrix<double, ublas::column_major> Acolwise(A);
 | |
| 		double *a = Acolwise.data().begin();
 | |
|     toc("householder_spqr: row->col");
 | |
| 
 | |
|     tic("householder_spqr: spqr_front");
 | |
| 		long npiv = min(m,n);
 | |
| 		double tol = -1;	long ntol = -1; // no tolerance is used
 | |
| 		long fchunk = m < 32 ? m : 32;
 | |
| 		char Rdead[npiv];  memset(Rdead, 0, sizeof(char)*npiv);
 | |
| 		double Tau[n];
 | |
| 		long b = min(fchunk, min(n, m));
 | |
| 		double W[b*(n+b)];
 | |
| 		double wscale = 0;
 | |
| 		double wssq = 0;
 | |
| 
 | |
| 		cholmod_common cc;
 | |
| 		cholmod_l_start(&cc);
 | |
| 
 | |
| 		// todo: do something with the rank
 | |
| 		long rank = spqr_front<double>(m, n, npiv, tol, ntol, fchunk,
 | |
| 				a, Stair, Rdead, Tau, W, &wscale, &wssq, &cc);
 | |
|     toc("householder_spqr: spqr_front");
 | |
| 
 | |
| //#ifndef NDEBUG
 | |
| 		for(long j=0; j<npiv; ++j)
 | |
| 		  if(Rdead[j]) {
 | |
| 		    cout << "In householder_spqr, aborting because some columns were found to be\n"
 | |
| 		        "numerically linearly-dependent and we cannot handle this case yet." << endl;
 | |
| 		    print(A, "The matrix being factored was\n");
 | |
| 		    ublas::matrix_range<ublas::matrix<double,ublas::column_major> > Acolsub(
 | |
| 		        ublas::project(Acolwise, ublas::range(0, min(m,n)), ublas::range(0,n)));
 | |
| 		    print(Matrix(ublas::triangular_adaptor<typeof(Acolsub), ublas::upper>(Acolsub)), "and the result was\n");
 | |
| 		    cout << "The following columns are \"dead\":";
 | |
| 		    for(long k=0; k<npiv; ++k)
 | |
| 		      if(Rdead[k]) cout << " " << k;
 | |
| 		    cout << endl;
 | |
| 		    exit(1);
 | |
| 		  }
 | |
| //#endif
 | |
| 
 | |
|     tic("householder_spqr: col->row");
 | |
| 		long k0 = 0;
 | |
| 		long j0;
 | |
| 		int k;
 | |
| 		memset(A.data().begin(), 0, m*n*sizeof(double));
 | |
| 		for(long j=0; j<n; j++, k0+=m) {
 | |
| 			k = k0;
 | |
| 			j0 = min(j+1,m);
 | |
| 			for(int i=0; i<j0; i++, k++)
 | |
| 				A(i,j) = a[k];
 | |
| 		}
 | |
| 
 | |
| //    ublas::matrix_range<ublas::matrix<double,ublas::column_major> > Acolsub(
 | |
| //        ublas::project(Acolwise, ublas::range(0, min(m,n)), ublas::range(0,n)));
 | |
| //    ublas::matrix_range<Matrix> Asub(ublas::project(A, ublas::range(0, min(m,n)), ublas::range(0,n)));
 | |
| //		ublas::noalias(Asub) = ublas::triangular_adaptor<typeof(Acolsub), ublas::upper>(Acolsub);
 | |
| 
 | |
|     toc("householder_spqr: col->row");
 | |
| 
 | |
| 		cholmod_l_finish(&cc);
 | |
| 
 | |
| 		if(allocedStair) delete[] Stair;
 | |
| 
 | |
| 		toc("householder_spqr");
 | |
| 	}
 | |
| 
 | |
| 	void householder_spqr_colmajor(ublas::matrix<double, ublas::column_major>& A, long *Stair) {
 | |
|     tic("householder_spqr");
 | |
| 
 | |
|     long m = A.size1();
 | |
|     long n = A.size2();
 | |
| 
 | |
|     assert(Stair != NULL);
 | |
| 
 | |
|     tic("householder_spqr: spqr_front");
 | |
|     long npiv = min(m,n);
 | |
|     double tol = -1;  long ntol = -1; // no tolerance is used
 | |
|     long fchunk = m < 32 ? m : 32;
 | |
|     char Rdead[npiv];  memset(Rdead, 0, sizeof(char)*npiv);
 | |
|     double Tau[n];
 | |
|     long b = min(fchunk, min(n, m));
 | |
|     double W[b*(n+b)];
 | |
|     double wscale = 0;
 | |
|     double wssq = 0;
 | |
| 
 | |
|     cholmod_common cc;
 | |
|     cholmod_l_start(&cc);
 | |
| 
 | |
|     // todo: do something with the rank
 | |
|     long rank = spqr_front<double>(m, n, npiv, tol, ntol, fchunk,
 | |
|         A.data().begin(), Stair, Rdead, Tau, W, &wscale, &wssq, &cc);
 | |
|     toc("householder_spqr: spqr_front");
 | |
| 
 | |
| //#ifndef NDEBUG
 | |
|     for(long j=0; j<npiv; ++j)
 | |
|       if(Rdead[j]) {
 | |
|         cout << "In householder_spqr, aborting because some columns were found to be\n"
 | |
|             "numerically linearly-dependent and we cannot handle this case yet." << endl;
 | |
|         print(A, "The matrix being factored was\n");
 | |
|         ublas::matrix_range<ublas::matrix<double,ublas::column_major> > Acolsub(
 | |
|             ublas::project(A, ublas::range(0, min(m,n)), ublas::range(0,n)));
 | |
|         print(Matrix(ublas::triangular_adaptor<typeof(Acolsub), ublas::upper>(Acolsub)), "and the result was\n");
 | |
|         cout << "The following columns are \"dead\":";
 | |
|         for(long k=0; k<npiv; ++k)
 | |
|           if(Rdead[k]) cout << " " << k;
 | |
|         cout << endl;
 | |
|         exit(1);
 | |
|       }
 | |
| //#endif
 | |
| 
 | |
|     cholmod_l_finish(&cc);
 | |
| 
 | |
|     toc("householder_spqr");
 | |
| 
 | |
| 	}
 | |
| 
 | |
| } // namespace gtsam
 | |
| #endif
 |