Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to calculate the indices generated by nested for loops?

I'm currently thinking about how to store frequently accessed data. It is meant to be stored in an array and is currently generated the following way.

public static void generateData() {

    int index = 0;
    for(int a1 = 0; a1 < 52; a1++) {
        for(int a2 = a1 + 1; a2 < 52; a2++) {
            for(int a3 = a2 + 1; a3 < 52; a3++) {
                for(int a4 = a3 + 1; a4 < 52; a4++) {
                    for(int a5 = a4 + 1; a5 < 52; a5++) {
                        for(int a6 = a5 + 1; a6 < 52; a6++) {
                            for(int a7 = a6 + 1; a7 < 52; a7++) {
                                data[index++] = compute(a1,a2,a3,a4,a5,a6,a7);
                            }
                        }
                    }
                }
            }
        }
    }
}

my issue is now to quickly access the computed data using the a1 to a7 parameters. The only approach I could think of is to iterate similar as during iteration time until the parameters are the same, like this

public static int getIndex(int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
    int index = 0;
    for(int a1 = 0; a1 < 52; a1++) {
        for(int a2 = a1 + 1; a2 < 52; a2++) {
            for(int a3 = a2 + 1; a3 < 52; a3++) {
                for(int a4 = a3 + 1; a4 < 52; a4++) {
                    for(int a5 = a4 + 1; a5 < 52; a5++) {
                        for(int a6 = a5 + 1; a6 < 52; a6++) {
                            for(int a7 = a6 + 1; a7 < 52; a7++) {

                                if(a1 == i1 && a2 == i2 && a3 == i3 && a4 == i4 && a5 == i5 && a6 == i6 && a7 == i7) {
                                    return index;
                                } else {
                                    index++;
                                }

                            }
                        }
                    }
                }
            }
        }
    }

    throw new IllegalArgumentException();
}

However this approach only runs at linear time, which isn't fast enough considering the amount of data. Because of that I was wondering if there is any way to calculate the index in constant or logarithmic time. As my question might seem quite vague. I'm storing all possible outcomes of each possible Texas hold'em hand to do some further testing.

like image 940
legendff Avatar asked Jan 05 '23 18:01

legendff


1 Answers

In your case index can be treated as a number in Combinatorial number system, where loop variables a1...a7 are the digits of this number.

formula of index

Here is a function that calculates index from given loop variables.

public static int getIndex(int a1, int a2, int a3, int a4, int a5, int a6, int a7) {
    return 133784559 - (C7[a1] + C6[a2] + C5[a3] + C4[a4] + C3[a5] + C2[a6] + (51 - a7));
}

static final int[] C2 = Ck(2), C3 = Ck(3), C4 = Ck(4), C5 = Ck(5), C6 = Ck(6), C7 = Ck(7);

// Creates a cache of C(51-i, k) for 0 <= i < 52
static int[] Ck(int k) {
    int[] result = new int[52];
    for (int i = 0; i < 52; i++) {
        result[i] = (int) C(51 - i, k);
    }
    return result;
}

// Computes binomial coefficient C(n, k)
static long C(int n, int k) {
    long C = 1;
    for (int i = 0; i < k; i++) {
        C = C * (n - i) / (i + 1);
    }
    return C;
}

getIndex method is pretty fast and requires only about 1K of extra static memory.

like image 55
apangin Avatar answered Jan 08 '23 07:01

apangin