Others have explained your specific difficulty but you did also ask how to make the code more compact/concise. The short answer is "Say no to loops!" (at least to the extent possible). Below is a partial, longer, answer.
There are several "C-isms" in your code that definitely could be made more concise. You use m
, sdf
and s
in the definition of your function, but don't define them until you reach the For
loop. It's a self-referential tangle, and being monolingual in Mathematica, I didn't know that one could even do this in languages like C.
I don't have time to do a full-scale refactor of your code, but here are some useful tips.
First, the For
loops. Have a look at the answers to this question, but more specifically, consider, for example this line from your nCk
definition:
For[ct = 1, ct <= rs, ct++, tot += s[[sdf[[ct]]]]]
You are just taking the sum of some parts of s
. Pretending I know nothing about s
or sdf
, I could still simplify this as:
tot = Plus@@ s[[Take[sdf,vz] ]]
You are just taking the parts 1 to rs
of sdf
and using those elements to define the parts of s
to use to create the summation tot
. Of course, looking at the definitions of sdf
and s
, they just seem to be Range
s anyway, so there are further simplifications you could try.
Another thing that makes your code more complicated than it needs to be is the double-Set
s inside the Block
: indx = ns = vy, i = rs = vz
. You don't then redefine ns
or rs
in the rest of the function definition, so why not just leave them out and use the vy
and vz
parameters passed to the function.
Here's another piece I don't understand: you have this definition in the nCr
function:
While[sdf[[i]] == indx && i > 1, --i; --indx]
But when you define sdf
just before invoking nCr
in the main loop, all it is is a Range
. At this point in nCr
it hasn't been altered, so you are checking if the $n$th element in a Range
vector equals $n$, which definitionally it will. You then get down to i==2
, increment sdf[[2]]
by 1 (so it's now 3), and increment i
by 1, so i
should now equal 3, at least if I'm following your code.
Here is the next line:
While[i <= vz, sdf[[i]] = sdf[[i - 1]] + 1; ++i;]
The first time this is invoked, isn't this just equivalent to incrementing the second through vs
th elemnts of sdf
by 1? You could almost certainly do this without a loop.
Finally, back to the main loop. Try putting a Print[s];
after the AppendTo
command, and then re-run the loop. I think you will find a whole bunch of excessive looping and redefining of s
.
I hope this is useful. Certainly, programming in Mathematica is very different to many other languages. It is one of the reasons that people coming from other languages find the learning curve so steep. But it is a very elegant language and in many ways can produce more readable code. Sure, pure function Slot
(#
) notation and some of the syntax forms can take some getting used to. But in my view, it is a darn sight easier to read than a bunch of nested For
and While
loops.