cfunction-pointerslatticelanczos

How to Pass a Large Data Set to a Function Without an Argument in C


I'm trying to create a general Lanczos algorithm that takes in an operator (function pointer) and prints a certain number of eigenvalues from that operator in C. I'm using the GNU Scientific Library to handle vectors and matrices. Specifically, the operator in question takes in some input vector and by-reference outputs a vector. So, I would expect the function prototype for the Lanczos method to minimally look something like,

void Lanczos( void (*operator) (gsl_vector_complex *,gsl_vector_complex *) , int k    );

Where k would be the number of eigenvalues I want printed. The issue is that the operator in question that I'm immediately interested in finding eigenvalues for needs to use a lot of external data that I generated in a previous simulation. Specifically, the operator that I'm interested in could be prototyped as

void WDoperator(gsl_vector_complex * input, gsl_vector_complex * output, lattice * L)

elsewhere in my program, I have the lattice and site structs defined as

typedef struct lattice{
  site * R[10*10*10*10];
}lattice;
typedef struct site{
  gsl_matrix_complex * link[4];
}site;

But of course, the way that it is written I can't pass a function pointer that looks like my WDoperator into Lanczos. My idea to solve this was to just have a global lattice pointer that holds my simulation results instead of passing it into WDoperator as an argument. However, while digging around on stackoverflow, it seems that the general consensus is to not use global variables and especially not global pointers. So, is there a better way of doing this that I'm not thinking of? Is there a way to "suppress" the argument of a function so it fits into a function pointer that my Lanczos routine will accept? If global pointers are the way to go with this, are there any best practices on using them so that I don't create a memory leaking monster? Especially considering the size of the data that would be stored in the lattice (40,000 matrices right now, but once I get it working I'd like to scale it up so it's on the order of 200k matrices). I apologize if there has been a similar question on here before, but I did my best to scope out the forum for similar queries.


Solution

  • A generally accepted mechanism is to provide an anonymous context parameter that gets passed through:

    void Lanczos( void (*operator) (gsl_vector_complex *,gsl_vector_complex *) , int k, void *ctx)
    void WDoperator(gsl_vector_complex * input, gsl_vector_complex * output, void * ctx) {
       Lattice *L = ctx;
    

    ...

    If you want to be a bit stricter with error checking, you could come up with something like:

    struct L_ctx {
        int type;
        void *arg;
    };
    enum {
        L_NoType,
        L_Lattice,
        L_ComplexLattice,
        ...
    };
    

    Then check that the appropriate type has been passed in. A little less error prone, but no match for a decent type system like Golang.