2

I have a math function that I would like to use in 1d, 2d, and 3d spaces. I wrote the code to work for the 3-d case and I can easily modify it for the other cases, however I was wondering if there is a way I can write this so that it works with any arbitrary dimensionality. Basically for every dimension there is another nested loop and I don't know how to make multiple nested loops without actually writing them out in the code.

void gen_kernel_Gk(double *Gk, double L, double b, int np, int Z, int m)
{
    // Generates Kernel Function G in k-space
    // Gk is the array of the function values, it has Z * m number of values
    // L is cuttoff distance
    // b is monomer size
    // np is the degree of polymerization
    // Z is the number of modes
    // m is the dimensionality of the real space

    int i, j, k, l, index, Zhalf;
    double pref, kvec[m], k2;

    pref = pow( 2 * PI / (double)L, 2) * pow( b, 2) * (double)np / 6.0;

    Zhalf = Z / 2;

    for( i = 0; i < Z; ++i)
    {
        if( i < Zhalf)
        {
            kvec[0] = (double) pow( i, 2);
        }
        else
        {
            kvec[0] = (double) pow ( Z - i ,2);
        }

        for( j = 0; j < Z; ++j)
        {
            if( i < Zhalf)
            {
                kvec[1] = (double) pow( j, 2);
            }
            else
            {
                kvec[1] = (double) pow ( Z - j ,2);
            }

            for( k = 0 ; k < Z ; ++k)
            {
                if( k < Zhalf)
                {
                    kvec[2] = (double) pow( k, 2);
                }
                else
                {
                    kvec[2] = (double) pow ( Z - k ,2);
                }

                for( k2 = 0, l = 0; l < m; ++l)
                {
                    k2 += kvec[l];
                }

                index = i * pow( Z, 2) + j * Z + k;
                Gk[index] = 2.0 * ( exp( -k2) + k2 - 1.0) / pow( k2, 2);
            } 
        }
    }
    return;
}
  • 1
    You can either use recursion, or you can use a stack the size of your dimensionality to store the loop variables and manage them there. Recursion would be simpler. – paddy Apr 13 '21 at 05:01
  • @paddy, I'm interested in seeing a solution. Recursion isn't my strong-suit, and I'm not even sure where to begin at the moment with the custom stack solution you mention, and which I'd also like to see. – Gabriel Staples Apr 13 '21 at 05:13
  • @GabrielStaples I added answer to show the principle for a solution based on recursion – Support Ukraine Apr 13 '21 at 08:13
  • examine mine [`bool nested_for(double *a0,double *a,double *a1,double *da,int &ix,int N)`](https://stackoverflow.com/a/21575035/2521214) it basically serialize all N nested for loops to single iteration call API ... its C++ but should be easily portable to C. If you want true [ND math](https://stackoverflow.com/a/55439139/2521214) and stuff then C is not good choice as you lack templates and classes... partially you can get around this with macros but only up to a point – Spektre Apr 13 '21 at 08:52

1 Answers1

1

If you want an arbitrary number of nested for loops, you can go for a solution that uses recursion.

Exactly how to do it depends on your specific task. The example below isn't based exactly on your code but it's a more general code example to show the principle. Hopefully you can see the idea and apply it to your specific task.

The basic idea is that the recursive function needs arguments that describe stuff like the number of dimensions and the size of each dimension (in an array) and the current level/index. For solving a specific task, you probably need to add additional arguments.

Like:

#include <stdio.h>
#include <assert.h>

void opr(const unsigned dimensions, const unsigned * dimsize, 
         unsigned curdim, unsigned * curindex)
{
  assert(curdim < dimensions);
  for (unsigned u = 0; u < dimsize[curdim]; ++u)
  {
    // Save the current index
    curindex[curdim] = u;

    // Check if the last dimension has been reached
    if (curdim == (dimensions - 1))
    {
      // yes, last dimension has been reached - now do the operation you want...
      // Here the code just do a simple print
      printf("Handle array element at ");
      for (unsigned t = 0; t < dimensions; ++t)
      {
        printf("[%u]", curindex[t]);
      }
      printf("\n");
    }
    else
    {
      // no, last dimension has NOT been reached
      // so do a recursive call for the next dimension
      opr(dimensions, dimsize, curdim + 1, curindex);
                    // notice: ^^^^^^^^^^ increase current dimension 
    }
  }
}

int main(void)
{
  unsigned dimsizeA[] = {2, 3};  // [2][3]
  unsigned dimensionsA = sizeof dimsizeA / sizeof dimsizeA[0];
  unsigned curindexA[] = {0, 0};
  opr(dimensionsA, dimsizeA, 0, curindexA);

  printf("-----------------------------------\n");

  unsigned dimsizeB[] = {2, 3, 3, 2};  // [2][3][3][2]
  unsigned dimensionsB = sizeof dimsizeB / sizeof dimsizeB[0];
  unsigned curindexB[] = {0, 0, 0, 0};
  opr(dimensionsB, dimsizeB, 0, curindexB);

  return 0;
}

Output:

Handle array element at [0][0]
Handle array element at [0][1]
Handle array element at [0][2]
Handle array element at [1][0]
Handle array element at [1][1]
Handle array element at [1][2]
-----------------------------------
Handle array element at [0][0][0][0]
Handle array element at [0][0][0][1]
Handle array element at [0][0][1][0]
Handle array element at [0][0][1][1]
Handle array element at [0][0][2][0]
Handle array element at [0][0][2][1]
Handle array element at [0][1][0][0]
Handle array element at [0][1][0][1]
Handle array element at [0][1][1][0]
Handle array element at [0][1][1][1]
Handle array element at [0][1][2][0]
Handle array element at [0][1][2][1]
Handle array element at [0][2][0][0]
Handle array element at [0][2][0][1]
Handle array element at [0][2][1][0]
Handle array element at [0][2][1][1]
Handle array element at [0][2][2][0]
Handle array element at [0][2][2][1]
Handle array element at [1][0][0][0]
Handle array element at [1][0][0][1]
Handle array element at [1][0][1][0]
Handle array element at [1][0][1][1]
Handle array element at [1][0][2][0]
Handle array element at [1][0][2][1]
Handle array element at [1][1][0][0]
Handle array element at [1][1][0][1]
Handle array element at [1][1][1][0]
Handle array element at [1][1][1][1]
Handle array element at [1][1][2][0]
Handle array element at [1][1][2][1]
Handle array element at [1][2][0][0]
Handle array element at [1][2][0][1]
Handle array element at [1][2][1][0]
Handle array element at [1][2][1][1]
Handle array element at [1][2][2][0]
Handle array element at [1][2][2][1]
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63