문제

I've been trying to find eigenvectors of a matrix by declaring ARPACK functions in C++ using extern "C":

extern "C" {void znaupd_(int *IDO, char *BMAT, int *N, char *WHICH,
                 int *NEV, double *TOL, complex<double> *RESID,
             int *NCV, complex<double> *V, int *LDV,
             int *IPARAM, int *IPNTR, complex<double> *WORKD,
             complex<double> *WORKL, int *LWORKL, 
             double *RWORK, int *INFO);}

extern "C" {void zneupd_(bool *RVEC, char *HOWMNY, bool *SELECT, 
             complex<double> *D, complex<double> *Z,
             int *LDZ, complex<double> *WORKEV, 
             complex<double> *SIGMA, char *BMAT, int *N,
             char *WHICH, int *NEV, double *TOL, 
             complex<double> *RESID, int *NCV, 
             complex<double> *V, int *LDV, int *IPARAM,
             int *IPNTR, complex<double> *WORKD, 
             complex<double> *WORKL, int *LWORKL, int *INFO);}

Then, in the body of my code, I call the functions:

  do{
    znaupd_(&IDO, &BMAT, &N, WHICH, &NEV, &TOL, RESID, &NCV, V, &LDV, IPARAM,
        IPNTR, WORKD, WORKL, &LWORKL, RWORK, &INFO);
    switch(abs(IDO)){
    case - 1:
      for(i = 0; i < N; i++) X[i] = WORKD[IPNTR[1] + i];
      gmm::mult(SM, X, Y);
      for(i = 0; i < N; i++) WORKD[IPNTR[2] + i] = Y[i];
      break;
    case 1:
      for(i = 0; i < N; i++) X[i] = WORKD[IPNTR[1] + i]; 
      gmm::mult(SM, X, Y);
      for(i = 0; i < N; i++) 
    {WORKD[IPNTR[2] + i] = Y[i];
      WORKD[IPNTR[3] + i] = X[i];}
      break;
    case 2:
      for(i = 0; i < N; i++)
    WORKD[IPNTR[2] + i] = WORKD[IPNTR[1] + i];
      break;
    }
  }while(IDO != 99);
  std::cout << &INFO << std::endl;
  zneupd_(&RVEC, &HOWMNY, SELECT, D, Z, &LDZ, WORKEV, &SIGMA, &BMAT, &N,
      WHICH, &NEV, &TOL, RESID, &NCV, V, &LDV, IPARAM, IPNTR, WORKD,
      WORKL, &LWORKL, &INFO);

After compiling and executing, however, the program segfaults. Carrying out a backtrace with GDB shows that the address being passed to zneupd_ by &INFO is 0x0, which causes the segfault when zneupd_ attempts to assign a new value to this position. When I move up to the next frame and use print &INFO, however, I am told that INFO is stored at register 0x28a27c. For some reason, my program is not passing the location of INFO to zneupd_ correctly. What is more perplexing is that znaupd_ is able to receive &INFO properly, and is able to access and modify the value at that location without problem. Can anybody tell me why one function can receive an argument properly, but the other cannot?

도움이 되었습니까?

해결책

You are probably reading a bad ARPACK documentation that has the wrong description of the ZNEUPD subroutine. In reality there is an additional argument RWORK before INFO (for a total of 24 arguments) and also SIGMA comes before WORKEV - see the official documentation and some source code. That &INFO comes as 0 in your case is just a lucky coincidence.

There is another problem in your code though - the C prototypes of the subroutines would be incorrect with most Fortran compilers on x86/x64. This is due to the fact that the CHARACTER arguments BMAT, WHICH and HOWMNY are character arrays (strings) and the length of each actual string argument is also passed by value as additional hidden argument of integer type. Therefore the prototype of ZNAUPD should be:

extern "C"
void znaupd_(int *IDO,
             char *BMAT,
             int *N,
             char *WHICH,
             int *NEV,
             double *TOL,
             complex<double> *RESID,
             int *NCV,
             complex<double> *V,
             int *LDV,
             int *IPARAM,
             int *IPNTR,
             complex<double> *WORKD,
             complex<double> *WORKL,
             int *LWORKL, 
             double *RWORK,
             int *INFO,
             int _BMAT,    // The length of the actual BMAT argument
             int _WHICH    // The length of the actual WHICH argument
            );

The same is true for ZNEUPD but it has three hidden integer arguments:

extern "C"
void zneupd_(bool *RVEC,
             char *HOWMNY,
             bool *SELECT, 
             complex<double> *D,
             complex<double> *Z,
             int *LDZ,
             complex<double> *SIGMA,
             complex<double> *WORKEV, 
             char *BMAT,
             int *N,
             char *WHICH,
             int *NEV,
             double *TOL, 
             complex<double> *RESID,
             int *NCV, 
             complex<double> *V,
             int *LDV,
             int *IPARAM,
             int *IPNTR,
             complex<double> *WORKD, 
             complex<double> *WORKL,
             int *LWORKL,
             double *RWORK,
             int *INFO,
             int _HOWMNY,
             int _BMAT,
             int _WHICH
            );
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top