C to VB/VBA

Hello all,

This is another combinatorial question from C to VB/VBA.

I found this code and since I'm illetatate with C
I would like your help translating the code.

How I understand this code is as follows:

1. Given a file that holds some sets of size 6, like:
{1,2,3,6,9,15}
{4,23,24,34,45}

2. The code below shall count how many sets from a parent set
{1,2,3...49}, are covered in such a way that at least
3plets, 4plets, 5plets and 6plets are included within
the sets of the given file.

3. It makes use of the Binomial Table c(49,6)

I do not understand how it accomplishes that count.
Any help/explanation or code will be greatly appreciated

Thanks,

/*
un programme qui prends un fichier input.dat contenant les
combinaisons a raison de 1 par ligne.
et qui a en argument le nombre de boules 6<= MAX <= 49

Cela permet de tester toutes les combinaisons sur des jeux reduits.

*/

#include <stdio.h>

#define LIM6 49
#define LIM5 (LIM6-1)
#define LIM4 (LIM6-2)
#define LIM3 (LIM6-3)
#define LIM2 (LIM6-4)
#define LIM1 (LIM6-5)

#define PRIVATE static
#define PROC void

#define EOT3 ((LIM6*LIM5*LIM4)/6)
#define EOT4 ((EOT3)*LIM3/4)
#define EOT5 ((EOT3)*(LIM3*LIM2)/20)
#define COMBIP2 ((LIM3*LIM2*LIM1)/6)
#define EOT  ((EOT3*COMBIP2)/20)   /* C(LIM6,6) */

#define ROLL(a0,a1,a2,a3,a4,a5,l) for (a5=5 ; a5 < l  ; a5++) \
for (a4=4 ; a4 < a5 ; a4++) \
for (a3=3 ; a3 < a4 ; a3++) \
for (a2=2 ; a2 < a3 ; a2++) \
for (a1=1 ; a1 < a2 ; a1++) \
for (a0=0 ; a0 < a1 ; a0++)

PRIVATE int base1[49] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48 } ;

PRIVATE int base2[49] = { 0, 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55,
66, 78, 91, 105, 120, 136, 153, 171, 190, 210, 231, 253, 276, 300, 325,
351, 378, 406, 435, 465, 496, 528, 561, 595, 630, 666, 703, 741, 780, 820,
861, 903, 946, 990, 1035, 1081, 1128 } ;

PRIVATE int base3[49] = { 0, 0, 0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220,
286, 364, 455, 560, 680, 816, 969, 1140, 1330, 1540, 1771, 2024, 2300, 2600,
2925, 3276, 3654, 4060, 4495, 4960, 5456, 5984, 6545, 7140, 7770, 8436, 9139,
9880, 10660, 11480, 12341, 13244, 14190, 15180, 16215, 17296 } ;

PRIVATE int base4[49] = { 0, 0, 0, 0, 1, 5, 15, 35, 70, 126, 210, 330, 495,
715, 1001, 1365, 1820, 2380, 3060, 3876, 4845, 5985, 7315, 8855, 10626, 12650,
14950, 17550, 20475, 23751, 27405, 31465, 35960, 40920, 46376, 52360, 58905,
66045, 73815, 82251, 91390, 101270, 111930, 123410, 135751, 148995, 163185,
178365, 194580 } ;

PRIVATE int base5[49] = { 0, 0, 0, 0, 0, 1, 6, 21, 56, 126, 252, 462, 792,
1287, 2002, 3003, 4368, 6188, 8568, 11628, 15504, 20349, 26334, 33649, 42504,
53130, 65780, 80730, 98280, 118755, 142506, 169911, 201376, 237336, 278256,
324632, 376992, 435897, 501942, 575757, 658008, 749398, 850668, 962598, 1086008,
1221759, 1370754, 1533939, 1712304 } ;

PRIVATE int base6[49] = { 0, 0, 0, 0, 0, 0, 1, 7, 28, 84, 210, 462, 924, 1716,
3003, 5005, 8008, 12376, 18564, 27132, 38760, 54264, 74613, 100947, 134596, 177100,
230230, 296010, 376740, 475020, 593775, 736281, 906192, 1107568, 1344904, 1623160,
1947792, 2324784, 2760681, 3262623, 3838380, 4496388, 5245786, 6096454, 7059052,
8145060, 9366819, 10737573, 12271512 } ;

PRIVATE int sol [EOT3] ;
#define ACCESOL(a,b,c) sol[base1[a]+base2[b]+base3[c] ]
#define SETSOL(a,b,c,d,e,f) ACCESOL(a,b,c)=1,ACCESOL(a,b,d)=1,ACCESOL(a,b,e)=1, \
ACCESOL(a,b,f)=1,ACCESOL(a,c,d)=1,ACCESOL(a,c,e)=1, \
ACCESOL(a,c,f)=1,ACCESOL(a,d,e)=1,ACCESOL(a,d,f)=1, \
ACCESOL(a,e,f)=1,ACCESOL(b,c,d)=1,ACCESOL(b,c,e)=1, \
ACCESOL(b,c,f)=1,ACCESOL(b,d,e)=1,ACCESOL(b,d,f)=1, \
ACCESOL(b,e,f)=1,ACCESOL(c,d,e)=1,ACCESOL(c,d,f)=1, \
ACCESOL(c,e,f)=1,ACCESOL(d,e,f)=1

#define SOLVED(a,b,c,d,e,f) ACCESOL(a,b,c)+ACCESOL(a,b,d)+ACCESOL(a,b,e)+\
ACCESOL(a,b,f)+ACCESOL(a,c,d)+ACCESOL(a,c,e)+\
ACCESOL(a,c,f)+ACCESOL(a,d,e)+ACCESOL(a,d,f)+\
ACCESOL(a,e,f)+ACCESOL(b,c,d)+ACCESOL(b,c,e)+\
ACCESOL(b,c,f)+ACCESOL(b,d,e)+ACCESOL(b,d,f)+\
ACCESOL(b,e,f)+ACCESOL(c,d,e)+ACCESOL(c,d,f)+\
ACCESOL(c,e,f)+ACCESOL(d,e,f)

main( argc, argv)
int argc;
char **argv;
{
register int t0,t1,t2,t3,t4,t5 ;
int n[6] ;
int res, num ;
char buffer[256] ;

FILE  *f;

int MAX ;

sscanf(argv[1],"%d",&MAX);
memset(sol,0,sizeof(sol)) ;

/* ouverture du fichier d'entree */
f = fopen("input.dat","r");

while (fgets(buffer,sizeof(buffer),f)) {
sscanf(buffer,"%d %d %d %d %d %d",&n[0],&n[1],&n[2],&n[3],&n[4],&n[5]) ;
for (t0=1;t0<6;t0++){
if (n[t0-1]>=n[t0]) {
printf (" combinaison incorrecte") ;
printf (" %2d %2d %2d %2d %2d %2d\n",n[0],n[1],n[2],n[3],n[4],n[5]);
exit(2) ;
}
}
SETSOL((n[0]-1),(n[1]-1),(n[2]-1),(n[3]-1),(n[4]-1),(n[5]-1)) ;
}
fclose(f);

/* verification ... */
num = 0 ;
ROLL(t0,t1,t2,t3,t4,t5,MAX) {
res=SOLVED(t0,t1,t2,t3,t4,t5) ;
if (!res) {
num++ ;
if (num <= 20)
printf("non verifiee : %2d %2d %2d %2d %2d %2d\n",
t0+1,t1+1,t2+1,t3+1,t4+1,t5+1) ;

}
}
printf (" **** non verifiee(s) : %d ****\n",num);
exit (0);
}
Who is Participating?

Commented:
While you were writing your comment, I was working on it. Read through it and see if it helps. It gives you full access to a possible VB-version of the algorithm and hopefully it makes you understand how the counting works. Thanks for the extra points, I appreciate that!

This will be a long night for you... :)

Let's get to work with these nasty-looking SETSOL and SOLVED macros. Macros tend to be the hardest to translate to other languages, but you may consider yourself lucky, these ones are not so hard.

First we start with SETSOL. It takes six parameters as you can see and it calls a lot of times into ACCESOL. And now that I look closely at it, I see that the previous way of creating the ACCESOL function is not sufficient. In C, the macro returns a reference to an item in the array and in this function that item is been set. We cannot do the same thing in VB, simply because VB does not have a mechanism for it. A workaround that I'll suggest here is to recreate the ACCESOL function into one that returns the member in the array that needs to be modified.

Function ACCESOL(a as Long, b As Long, c As Long) As Long
ACCESOL = base1(a) + base2(b) + base3(c)
End Function

Sub SETSOL(a as Long, b As Long, c As Long, d as Long, e As Long, f As Long)
sol(ACCESOL(a,b,c)) = 1
sol(ACCESOL(a,b,d)) = 1
sol(ACCESOL(a,b,e)) = 1
....<repeat for every combination of three out of (a,b,c,d,e,f)>
End Sub

We are nearly done. The only thing to do now is create the SOLVED function and solve the problem with the for-loop in the ROLL-macro, which will hardly prove to be a problem here.
First, SOLVED is just a sum of those same combinations we've just initialized to one in SETSOL, but with other values for a..f. SETSOL is only called with the data from the input.dat file, the SOLVED function is called with ANY data between zero and MAX. And the latter is a value that you'd give the original program on the commandline.

Function SOLVED(a as Long, b As Long, c As Long, d as Long, e As Long, f As Long) As Long
SOLVED = _
sol(ACCESOL(a,b,c)) + sol(ACCESOL(a,b,d)) + _
sol(ACCESOL(a,b,e)) + sol(ACCESOL(a,b,d)) + _
....<repeat for every combination of three out of (a,b,c,d,e,f)>

End Function

Now that we have had the most difficult parts out of the way, it will probably become much clearer on how the system works. I'll present you below some pseudo-code to work out your way. It will make the ROLL-macro understandable and it will give you even more insight in the workings of the program.
An important note when you start working with it: that base4,5 and 6 are never used. You may now why that is, but I don't. It probably has something to do with the chosen algorithm implementation, or the number of permutations became to high and the programmer didn't want to tend to that. Who knows :)
Here's some pseudocode for the main part of the program:

'Start program
Dim t0..t5 As Long
Dim n(6) As Long
Dim res As Long, num As Long
Dim buffer As String
Dim fFile As Integer
Dim MAX As Long

MAX = Command()            'sscanf...
'memset initializes the arrays to zero. In C that's needed, in VB it is not.

fFile = FreeFile
Open "input.dat" As #fFile

While Not EOF(fFile)
ReadIntoArrayOneLine(n)    'Read six numbers at a time into n
'Test the input for correctness (see prev. comment)
If IncorrectInput() Then
End
End If

SETSOL n(0)-1, n(1)-1.....n(5)-1
Wend
Close #fFile

'This is where the ROLL macro comes into play

For t5 = 5 To MAX - 1
For t4 = 4 To t5 - 1
For t3 = 3 To t4 - 1
For t2 = 2 To t3 - 1
For t1 = 1 To t2 - 1
For t0 = 0 To t1 - 1
res = SOLVED(t0, t1, t2, t3, t4, t5)
If res <> 0 Then
....
Else
num = num + 1
If num <= 20 Then
PrintSomewhere "non verifiee data: " & somedata
'Log the non verifiee here
End If
End If
Next t0
Next t1
Next t2
Next t3
Next t4
Next t5

PrintSomewhere " **** non verifiee(s) " & num

'End of program

Hopefully this helped you a little.

Regards,
Abel

0

Commented:
I can translate sentence for sentence for you, though I do not understand what the whole program is about.

Do you mean with Binom. Table (49,6) the binomial coefficient, like (49,6) = 49! / (6! * (49 - 6)!) = 13983816?

For starters, you can declare baseX as fixed arrays from 0 to 49 and fill them with the data.
For the #defines we can work out some functions
Every int is a long in VB, you can ignore the term "register". This way you get statements like this:

"register int t0,t1,t2,t3,t4,t5;" becomes:
Dim t0 As Long, t1 As Long, t2 As Long etc.

If you see something like n[6], then this is a fixed 0-based array:
Dim n(0 To 6) As Long

Use VB's Open statement for "input.dat" and read each line, filled with (as you stated) six numbers, into n. The for-loop you find there checks if any number is indeed lower then the previous number. In VB this looks like this:

For i = 1 To 5
If n(i - 1) <= n(i) Then
MsgBox "Error"
End If
Next i

If you're still with me and you want me to help you further I'll continue with translating the macro SETSOL.

A final notice, the code you posted contains errors. For example, the main() statement is incorrect. Do you have the correct URL where to find this code including a sample input.dat? With a correct version I can more easily translate it.

Regards,
Abel
0

Commented:
Btw, it is not a compact C++ program. The writer could have used arrays much more and much smarter, making it overall easier to read.
0

Author Commented:
Hi abel,

The web page is : http://membres.lycos.fr/coustaux/lotto-prg.html

The link to the code is: " Un programme de test de couverture a 3 "

or directly to the code : http://membres.lycos.fr/coustaux/prg/cov3.c

The table is the Binomial Coefficients for the given parameters.
This is easy to generate:

For I = 0 To 49: BinTab(I, 1) = I: Next
For J = 1 To 5
For I = J To V
BinTab(I, J) = BinTab(I - 1, J) + BinTab(I - 1, J - 1)
Next
Next

What the program does:
This program shall identify how many sets from the total of  49c6  ~14 mil
are "covered" by the sets in the file "input.dat" in at least 3 points
By "covered" I mean the following:

Each set in the file can "cover" from the total field
at least in 3 points:= 6c3 * 43c3=20*12341=246,820 combinations from 49c6
at least in 4 points:= 6c4 * 43c2=15*903=13545 combinations
at least in 5 points:= 6c5 * 43c1=6*43=258
and       in 6 points:= 6c6 *43c0=1*1=1
For a total of  260,624 combinations
So each set covers so many combinations (260,624) in at least 3 points.
But the collection of sets in the file, how many total combinations "cover"?

This program can calculate that faster than going through a "brute force" procedure.

The program can be used to rank combinations (sets) according to their "covering" properties.

I'm trying to understand how this is accomplished.

Any help is very much appreciated.

nakoutra
0

Author Commented:
Hi abel,

The web page is : http://membres.lycos.fr/coustaux/lotto-prg.html

The link to the code is: " Un programme de test de couverture a 3 "

or directly to the code : http://membres.lycos.fr/coustaux/prg/cov3.c

The table is the Binomial Coefficients for the given parameters.
This is easy to generate:

For I = 0 To 49: BinTab(I, 1) = I: Next
For J = 1 To 5
For I = J To V
BinTab(I, J) = BinTab(I - 1, J) + BinTab(I - 1, J - 1)
Next
Next

What the program does:
This program shall identify how many sets from the total of  49c6  ~14 mil
are "covered" by the sets in the file "input.dat" in at least 3 points
By "covered" I mean the following:

Each set in the file can "cover" from the total field
at least in 3 points:= 6c3 * 43c3=20*12341=246,820 combinations from 49c6
at least in 4 points:= 6c4 * 43c2=15*903=13545 combinations
at least in 5 points:= 6c5 * 43c1=6*43=258
and       in 6 points:= 6c6 *43c0=1*1=1
For a total of  260,624 combinations
So each set covers so many combinations (260,624) in at least 3 points.
But the collection of sets in the file, how many total combinations "cover"?

This program can calculate that faster than going through a "brute force" procedure.

The program can be used to rank combinations (sets) according to their "covering" properties.

I'm trying to understand how this is accomplished.

Any help is very much appreciated.

nakoutra
0

Commented:
I see now that you copied it correctly and the source is correct as well. I just didn't see that is was a C file. I just assumed it was a C++ file.

I understand now what you mean and basically what the program does. I'll update quickly after this.
0

Commented:
Hmmm, do not refresh your browser, just hit "Reload Question" on top-right of the page. That way you won't see your comments copied more then once into the thread.
0

Commented:
Before I continue, do you understand the basic structure of the program and how to translate? Or do you want me to just give you a fully working VB program based on this C-program?

If there are only certain parts that you don't understand and want translated it will of course be quicker to go through it all.
0

Commented:
I continue anyway:

The first #defines are just constants. In VB that looks like this:

Const LIM6 As Long = 49
Const LIM5 As Long = LIM6 - 1
...etc.

You can ignore the #defines PRIVATE and PROC (odd use of the word PRIVATE here, but that's another story).
The #defines EOT3...EOT are again constants:

Const EOT3 As Long = ((LIM6 * LIM5 * LIM4) /6)
....etc.

Here's an interesting thing. The programmer creates floating point variables here, maybe without knowing. He does nothing to prevent the overhead of doubles, though at other points he tries to instruct the compiler to optimize for speed.

Now we come to the first "functional" #define, called a macro in C-terms. We also come to our first problem here, because this one is not directly convertable to a function or sub in VB. That is, because this macro only expands to the start of a complex loop (you see al these for-statements, that's six loops in one). Usually programmers don't create this kind of macros, simply because they confuse reading the code. I'll come back to this ROLL-macro when we'll need it.

Next you see a lot of PRIVATEs, which basically aren't private, but public. Hence my remark earlier on. Create arrays of these like I said before:
Dim base1(0 To 49) As Long

If you have no Option Base 1, you can ignore the "0 To"-part. Do the same for base2 to base6. Also, use your regular VB-skills to fill the arrays with the data. You may want to put the data (between brackets in the .c file) in files and then read it in, otherwise it may become quite long using VB statements.
You may consider using the Array-statement. But beware, if this becomes quite a computational program, you must know that accessing a variant array is much-much slower then accessing a normal array. And the Array()-statement can only return a variant-array! One way to workaround this issue is to copy the results of the Array-statement into the normal array using a loop. But that's up to you.

The last one, that array sol can be declared without initializing it (I won't be using the "0 To" from now on, ok?)
Dim sol(EOT3) As Long

Again, we come across some functional macros. The first one now, the latter is for the next posting. I don't like too long postings, those are often too hard to read.
Now, this ACCESOL macro just "returns" (it doesn't really do that, but let's pretend it does, otherwise this will end up being a course in C) a calculated value based on three input integers. In VB this looks like this:

Function ACCESOL(a as Long, b As Long, c As Long)
ACCESOL = sol(base1(a) + base2(b) + base3(c))
End Function

Hope this is what you want,

Regards,
Abel
0

Author Commented:
Hello Abel,

Firstly I will increase the points to 600
Your work into teaching me the conversion is worth it.
300 extra points will be rewarded to you as "points for Abel"

The main purpose of this exercise shall be:
- To understand how this program works to accomplish the task.
- To understand the requirements for translating some  C code  to VB

It is not clear to me yet how it accomplishes the count.
This is my priority.  If you have recognized this I'll be very glad if you
can explain it to me.

I will follow all the notes you provided.
I'll work on this tonight.

Thanks,
nakoutra

0

IT OperationsCommented:
Interesting...
0

Commented:
I heard that the emailing system was down, so just to let you know there was an update in this thread (hope emailing works again): ping :)
0

Author Commented:
Hello Abel,

Yes I couldn't connect yesterday.

The final word about the program is that it does not
do what I was wishing for.

It only finds the 3plets covered by the file "input.dat"
and not "at least 3 if 6".

There are better was to accomplish what the author was trying to.

Thank you very much.

I'll accept your answer and award you the extra points too.

Thanks again,
nakoutra
0

Commented:
Maybe you remember my remark about the unused arrays? If you utilize them, and if you look carefull through the code, it will go through all six! But it will of course take much more processing time, it probably increases exponentially. And that might also have been the reason why the author did not include those arrays: too slow. Or he just found it too tedious to work through all the combinations in the SETSOL macro.

Hopefully you have at least gained a better understanding on how things work in this algorithm. And if you still have questions, I'm still around :)

Cheers,
Abel
0

Commented:
Btw, thanks for the grade and the points, it was fun working with you :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.