📄 vnl_sparse_symmetric_eigensystem.cxx
字号:
// This is core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx
#ifdef VCL_NEEDS_PRAGMA_INTERFACE
#pragma implementation
#endif
//:
// \file
#include "vnl_sparse_symmetric_eigensystem.h"
#include <vcl_cassert.h>
#include <vcl_cstring.h>
#include <vcl_iostream.h>
#include <vcl_vector.h>
#include "vnl_netlib.h" // dnlaso_()
static vnl_sparse_symmetric_eigensystem * current_system = 0;
#ifdef VCL_SUNPRO_CC
# define FUNCTION extern "C"
#else
# define FUNCTION static
#endif
//------------------------------------------------------------
//: Callback for multiplying our matrix by a number of vectors.
// The input is p, which is an NxM matrix.
// This function returns q = A p, where A is the current sparse matrix.
FUNCTION
void sse_op_callback(const int* n,
const int* m,
const double* p,
double* q)
{
assert(current_system != 0);
current_system->CalculateProduct(*n,*m,p,q);
}
//------------------------------------------------------------
//: Callback for saving the Lanczos vectors as required by dnlaso.
// If k=0, save the m columns of q as the (j-m+1)th through jth
// vectors. If k=1 then return the (j-m+1)th through jth vectors in
// q.
FUNCTION
void sse_iovect_callback(const int* n,
const int* m,
double* q,
const int* j,
const int* k)
{
assert(current_system != 0);
if (*k==0)
current_system->SaveVectors(*n,*m,q,*j-*m);
else if (*k==1)
current_system->RestoreVectors(*n,*m,q,*j-*m);
}
vnl_sparse_symmetric_eigensystem::vnl_sparse_symmetric_eigensystem()
: nvalues(0), vectors(0), values(0)
{
}
vnl_sparse_symmetric_eigensystem::~vnl_sparse_symmetric_eigensystem()
{
delete[] vectors; vectors = 0;
delete[] values; values = 0;
for (unsigned i=0; i<temp_store.size(); ++i)
delete temp_store[i];
temp_store.clear();
}
//------------------------------------------------------------
//: Here is where the fortran converted code gets called.
// The sparse matrix M is assumed to be symmetric. The n smallest
// eigenvalues and their corresponding eigenvectors are calculated if
// smallest is true (the default). Otherwise the n largest eigenpairs
// are found. The accuracy of the eigenvalues is to nfigures decimal
// digits. Returns 0 if successful, non-zero otherwise.
int vnl_sparse_symmetric_eigensystem::CalculateNPairs(vnl_sparse_matrix<double>& M,
int n,
bool smallest,
int nfigures)
{
mat = &M;
// Clear current vectors.
if (vectors) {
delete[] vectors; vectors = 0;
delete[] values; values = 0;
}
nvalues = 0;
current_system = this;
int dim = mat->columns();
int nvals = (smallest)?-n:n;
int nperm = 0;
int nmval = n;
int nmvec = dim;
vcl_vector<double> temp_vals(n*4);
vcl_vector<double> temp_vecs(n*dim);
// set nblock = vcl_max(10, dim/6) :
int nblock = (dim<60) ? dim/6 : 10;
// isn't this rather a lot ? -- fsm
int maxop = dim*10; // dim*20;
// set maxj = vcl_max(40, maxop*nblock, 6*nblock+1) :
int maxj = maxop*nblock; // 2*n+1;
int t1 = 6*nblock+1;
if (maxj < t1) maxj = t1;
if (maxj < 40) maxj = 40;
// Calculate size of workspace needed. These expressions come from
// the LASO documentation.
int work_size = dim*nblock;
int t2 = maxj*(2*nblock+3) + 2*n + 6 + (2*nblock+2)*(nblock+1);
if (work_size < t2) work_size = t2;
work_size += 2*dim*nblock + maxj*(nblock + n + 2) + 2*nblock*nblock + 3*n;
vcl_vector<double> work(work_size+10);
// Set starting vectors to zero.
for (int i=0; i<dim*nblock; ++i)
work[i] = 0.0;
vcl_vector<int> ind(n);
int ierr = 0;
dnlaso_(sse_op_callback, sse_iovect_callback,
&dim, &nvals, &nfigures, &nperm,
&nmval, &temp_vals[0],
&nmvec, &temp_vecs[0],
&nblock,
&maxop,
&maxj,
&work[0],
&ind[0],
&ierr);
if (ierr > 0) {
if (ierr & 0x1) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: N < 6*NBLOCK\n";
}
if (ierr & 0x2) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NFIG < 0\n";
}
if (ierr & 0x4) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NMVEC < N\n";
}
if (ierr & 0x8) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NPERM < 0\n";
}
if (ierr & 0x10) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: MAXJ < 6*NBLOCK\n";
}
if (ierr & 0x20) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL < max(1,NPERM)\n";
}
if (ierr & 0x40) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL > NMVAL\n";
}
if (ierr & 0x80) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL > MAXOP\n";
}
if (ierr & 0x100) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL > MAXJ/2\n";
}
if (ierr & 0x200) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NBLOCK < 1\n";
}
}
else if (ierr < 0) {
if (ierr == -1) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem:\n"
<< " poor initial vectors chosen\n";
}
else if (ierr == -2) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem:\n"
<< " reached maximum operations " << maxop
<< " without finding all eigenvalues,\n"
<< " found " << nperm << " eigenvalues\n";
}
else if (ierr == -8) {
vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem:\n"
<< " disastrous loss of orthogonality - internal error\n";
}
}
// Copy the eigenvalues and vectors.
nvalues = n;
vectors = new vnl_vector<double>[n];
values = new double[n];
for (int i=0; i<n; ++i) {
values[i] = temp_vals[i];
#if 0
vcl_cout << "value " << temp_vals[i]
<< " accuracy " << temp_vals[i+n*2] << vcl_endl;
#endif
vnl_vector<double> vec(dim,0.0);
for (int j=0; j<dim; ++j)
vec[j] = temp_vecs[j + dim*i];
vectors[i] = vec;
}
// Delete temporary space.
for (unsigned i=0; i<temp_store.size(); ++i)
delete [] temp_store[i];
temp_store.clear();
return ierr;
}
//------------------------------------------------------------
//: Callback from solver to calculate the product A p.
int vnl_sparse_symmetric_eigensystem::CalculateProduct(int n, int m,
const double* p,
double* q)
{
// Call the special multiply method on the matrix.
mat->mult(n,m,p,q);
return 0;
}
//------------------------------------------------------------
//: Callback to store vectors for dnlaso.
int vnl_sparse_symmetric_eigensystem::SaveVectors(int n, int m,
const double* q,
int base)
{
// Store the contents of q. Basically this is a fifo. When a write
// with base=0 is called, we start another fifo.
if (base == 0) {
for (unsigned i=0; i<temp_store.size(); ++i)
delete temp_store[i];
temp_store.clear();
}
double* temp = new double[n*m];
vcl_memcpy(temp,q,n*m*sizeof(double));
// vcl_cout << "Save vectors " << base << " " << temp << vcl_endl;
temp_store.push_back(temp);
return 0;
}
//------------------------------------------------------------
//: Callback to restore vectors for dnlaso.
int vnl_sparse_symmetric_eigensystem::RestoreVectors(int n, int m,
double* q,
int base)
{
// Store the contents of q. Basically this is a fifo. When a read
// with base=0 is called, we start another fifo.
static int read_idx = 0;
if (base == 0)
read_idx = 0;
double* temp = temp_store[read_idx];
vcl_memcpy(q,temp,n*m*sizeof(double));
// vcl_cout << "Restore vectors " << base << " " << temp << vcl_endl;
read_idx++;
return 0;
}
//------------------------------------------------------------
//: Return a calculated eigenvector.
vnl_vector<double> vnl_sparse_symmetric_eigensystem::get_eigenvector(int i) const
{
assert(i>=0 && i<nvalues);
return vectors[i];
}
double vnl_sparse_symmetric_eigensystem::get_eigenvalue(int i) const
{
assert(i>=0 && i<nvalues);
return values[i];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -