0

I'm trying to make this function called walk in C. The idea is that the function takes as parameters a point in space (represented by an array), a function (pointer), and a step size / learning rate and moves from the provided point in a direction that minimizes the provided function. The problem that I faced is regarding the input function. In my particular case, the function that should be provided to walk needs to handle variables (not function variables) that are provided at run time. In my case, the variables are the training data set and the labels. And the variables of the function that should be provided to walk are different from these. (they are the model's parameters)

As an example, the function that could be provided to walk can be defined as such:

int foo(int* X, int X_size, int alpha, int beta) {
    ret = 0;
    for(int k = 0; k < X_size; k++) {
        ret = ret + X[k]*X[k]*alpha + beta;  
    }
    return ret;
}

void walk(int* X, int X_size, float step_size, int (*function)(// function variables)) {
   // some instructions
}

foo is meant to represent a multidimensional function of X, while alpha and beta are mere parameters that are defined at runtime. The problem with this sort of definition is that walk should be hardcoded to know in respect to which variable should the provided function be differentiated, which violates the principle of separation of concerns. It also needs to receive the parameters alpha and beta as variables in order to pass them to function. This doesn't scale well when there is a different number of parameters.

I thought of defining beta and alpha as global variables so that I could define foo as int foot(int* X, int X_size) and then walk as:

void walk(int* X, int X_size, float step_size, int (*function)(int* X, int X_size));

But I'm reluctant to use global variables as they tend to come with their own set of problems. If this helps, I intend to make this as a toy library for machine learning.

Is there a better a way that I could go about implementing this? Let me know if I need to add more context or clarifications.

1 Answer 1

3

in C, every callback should get a void* parameter to allow such decoupling. Then you can pass the address of a structure containing the parameters you need:

struct foo_data {
    int alpha;
    int beta;
};
int foo(int* X, int X_size, void *data_) {
    struct foo_data *data = data_;
    ret = 0;
    for(int k = 0; k < X_size; k++) {
        ret = ret + X[k]*X[k]*data->alpha + data->beta;
    }
    return ret;
}

void walk(
    int* X, int X_size, float step_size,
    int (*function)(/*function variables*/, void *function_data),
    void *function_data
) {
   // some instructions
}

int main() {
    struct foo_data foo_data;
    foo_data.alpha = 1234;
    foo_data.beta = 5678;
    walk(X, X_size, step_size, foo, &foo_data);
}

This can be rather unwieldy, but it's the best way to accomplish this in C.

Alternatively, you can make them global. It is not a matter of "safety" but rather a matter of flexibility. If you eventually need more than one alpha and beta, especially if you need them at the same time, you will be disappointed if you make them global variables now. If you know you won't, then it can be okay. The larger and more complex your program is, the worse it is to use global variables.

1
  • 1
    "The larger and more complex your program is, the worse it is to use global variables." is an interesting point that I haven't seen mentioned in many places. A small program acts a bit like a class. Global variables are just class member variables.
    – user253751
    Mar 27, 2023 at 9:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.