1

I installed Arpack using "sudo apt install libarpack2-dev".

Next libraries are present in /usr/lib:

libarpack.a,
libarpack.so,
libarpack.so.2,
libarpack.so.2.0.0

I want to call the dsaupd subroutine in this library from a cpp file called ising.cpp.

When running "make --debug" I get the error

undefined reference to `dsaupd_'
collect2: error: ld returned 1 exit status

I am too inexperienced in calling subroutines from fortran libs to figure out where the problem is.

Which modification are needed:

  • to resolve the undefined reference error
  • to successfully call the subroutine

Edit: First part seems solved at first sight by putting the l-flags after the cpp file. This changes the g++ command to

g++ -g -O3 -mavx2 -funroll-loops -std=c++17 -o ising.exe ising.cpp -lblas -llapack -larpack -lgfortran

This is related to this question.

After being able to compile the code I still struggled with calling the subroutine. When running the program, I had "17713 Segmentation fault (core dumped)"

It seems that this issue is related to this question, which basically boils down to mismatch in pass by value (C++) VS pass by reference (fortran).

The complete output of the make command (including actual g++ call) is (was)

GNU Make 4.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Updating goal targets....
 File 'all' does not exist.
   File 'ising.exe' does not exist.
  Must remake target 'ising.exe'.
g++ -g -O3 -mavx2 -funroll-loops -std=c++17 -lblas -llapack -larpack -lgfortran -o ising.exe ising.cpp
/tmp/ccyV1Kcn.o: In function `main':
/home/josja/Programs/Ising/ising.cpp:45: undefined reference to `dsaupd_'
collect2: error: ld returned 1 exit status
Makefile:7: recipe for target 'ising.exe' failed
make: *** [ising.exe] Error 1

The arpack routine I want to call is this routine:

c-----------------------------------------------------------------------
c\BeginDoc
c
c\Name: dsaupd 
c
c\Description: 
...
c  dsaupd  is usually called iteratively to solve one of the 
c  following problems:
c
c  Mode 1:  A*x = lambda*x, A symmetric 
c           ===> OP = A  and  B = I.
...
c\Usage:
c  call dsaupd  
c     ( IDO, BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM,
c       IPNTR, WORKD, WORKL, LWORKL, INFO )
c
c\Arguments
c  IDO     Integer.  (INPUT/OUTPUT)
...             
c  BMAT    Character*1.  (INPUT)
...
c  N       Integer.  (INPUT)
...
c  WHICH   Character*2.  (INPUT)
...
c  NEV     Integer.  (INPUT)
...
c  TOL     Double precision  scalar.  (INPUT)
...
c  RESID   Double precision  array of length N.  (INPUT/OUTPUT)
...
c  NCV     Integer.  (INPUT)
...
c  V       Double precision  N by NCV array.  (OUTPUT)
...
c  LDV     Integer.  (INPUT)
...
c  IPARAM  Integer array of length 11.  (INPUT/OUTPUT)
...
c  IPNTR   Integer array of length 11.  (OUTPUT)         -------------------------------------------------------------
...
c  WORKD   Double precision  work array of length 3*N.  (REVERSE COMMUNICATION)
...
c  WORKL   Double precision  work array of length LWORKL.  (OUTPUT/WORKSPACE)
...
c  LWORKL  Integer.  (INPUT)
...
c  INFO    Integer.  (INPUT/OUTPUT)
...
c-----------------------------------------------------------------------
c
      subroutine dsaupd 
     &   ( ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, 
     &     ipntr, workd, workl, lworkl, info )
c
c     %----------------------------------------------------%
c     | Include files for debugging and timing information |
c     %----------------------------------------------------%
c
      include   'debug.h'
      include   'stat.h'
c
c     %------------------%
c     | Scalar Arguments |
c     %------------------%
c
      character  bmat*1, which*2
      integer    ido, info, ldv, lworkl, n, ncv, nev
      Double precision 
     &           tol
c
c     %-----------------%
c     | Array Arguments |
c     %-----------------%
c
      integer    iparam(11), ipntr(11)
      Double precision 
     &           resid(n), v(ldv,ncv), workd(3*n), workl(lworkl)
c
c     %------------%
c     | Parameters |
c     %------------%
c
      Double precision 
     &           one, zero
      parameter (one = 1.0D+0 , zero = 0.0D+0 )
c
c     %---------------%
c     | Local Scalars |
c     %---------------%
c
      integer    bounds, ierr, ih, iq, ishift, iupd, iw, 
     &           ldh, ldq, msglvl, mxiter, mode, nb,
     &           nev0, next, np, ritz, j
      save       bounds, ierr, ih, iq, ishift, iupd, iw,
     &           ldh, ldq, msglvl, mxiter, mode, nb,
     &           nev0, next, np, ritz

The cpp file from which I want to call the routine is ising.cpp. This here is a version that avoids the aforementioned segmentation faults.

#include <iostream>
#include <bitset>
#include <string>
#include <vector>
using namespace std;

...

extern"C" {
void dsaupd_(int & IDO, char & BMAT, int & N, char WHICH[2], int & NEV,
    double & TOL, double * RESID, int & NCV, double * V, int & LDV,
    int IPARAM[11], int IPNTR[11], double * WORKD,
    double * WORKL, int & LWORKL, int & INFO );
}

int main(int argc, char *argv[]) {
    ...
    int ido = 0;            // Reverse communication flag. (in/out-)
    char bmat = 'I';        // Normal eigenvalue equation. (in)
    int n = 1<<L;           // Dimension of the eigenproblem. (in)
    char which[3] = "SM";   // Compute smallest (in magnitude) eigenvalues. (in)
    int nev = 4;            // Number of eigenvalues to be computed. (in)
    double tol = 0;         // Tolerated error on the eigenvalues. (in)

    double resid[n];        // Will contain the final residual vector. (in/out)
    int ncv = min(n, max(2*nev + 1, 20));   // Number of Lanczos vectors. (in)
    double v[n*ncv];        // Will contain the Lanczos vectors. (out)
    int ldv = n;            //???? Leading dimension of v.??? (in)
    int iparam[11];         // Itaration parameters: (in)
        iparam[0] = 1;          // Exact shifts are used.
        iparam[2] = 300;        // Maximum number of Arnoldi iterations allowed.
        iparam[6] = 1;          // Mode 1 of dsaupd (normal eigenvalue equation).
    int ipntr[11];          // Pointers inside working spaces. (work)
    double workd[3*n];      // Workspace that will contain residuals. (out/work)
    int lworkl = ncv*(ncv+8);   // Size of private workspace. (in/work)
    double workl[lworkl];       // Private workspace. (work)
    int info = 0;           // Randomly initial residual vector is used. (in/out)

    dsaupd_(ido, bmat, n, which, nev, tol, resid, ncv, v, ldv,
            iparam, ipntr, workd, workl, lworkl, info );

    ...
}

...

To stackoverflow: please allow questions to be submitted. Your tools to properly recognize code blocks doesn't work and lead to refusing usefull questions and destroying the lay-out of questions.

Josja
  • 131
  • 7
  • 2
    Order of compiler flags matters here. `-l` come *after* .cpp files. – HolyBlackCat May 10 '19 at 09:32
  • _"To stackoverflow: please allow questions to be submitted. Your tools to properly recognize code blocks doesn't work and lead to refusing usefull questions and destroying the lay-out of questions"_ It works just fine; we get many thousands of questions every day. If you found a bug, post it on [meta]. – Lightness Races in Orbit May 10 '19 at 11:10
  • If people don't like the lay-out of a question. It's their problem, they can just neglect it. My question was first refused because the "code block" libarpack.a etc. which is no code was not intended as code and if I was not as good in debugging I would not be able to finally post it. The goal of my question is to actually succeed in calling that subroutine and I reformulated part(!) of the question because of a partial(!) answer. So please think twice before marking a question as duplicated. – Josja May 10 '19 at 13:20

0 Answers0