4

For any positive integer $n$ which is not specified a priori, I can make $n$-tuple vector $v$ by v = Array[a, 1, n]. Now, given that $n$ is a positive integer which is not specified a priori, I want to write an iteration sentence which performs over $1\leq a_1,\ldots, a_n\leq 3$. ($a_i$ are integers and hence I will get $3^n$ iterations).

For example, if $n=2$, my sentence plays the same role as the following loop:

Do[EXPERIMENT, {i, 3}, {j, 3}]

If $n=3$, my sentence plays the same role as the following:

Do[EXPERIMENT, {i, 3}, {j, 3}, {k, 3}].

I can do it for any given SPECIFIED integer $n$, but I want to write the universal looping sentence which iterates for $1\leq a_1,\ldots, a_n\leq 3$ ($a_i$ are integers.)

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
newbie0823
  • 41
  • 2

2 Answers2

3

Following belisarius' suggestion you might use something like:

SetAttributes[f, HoldFirst]

f[body_, n_Integer?Positive, m__:3] := Block[{a},
  Do[body, ##] & @@ Thread[{Array[a, n], m}]
]

Use:

f[Print[a[1], a[2], a[3]], 3]

f[Print[a[1], a[2]], 2, 4]

f[Print[a[1], a[2]], 2, 5, 7]

How are parameters evaluated for a Plot in Manipulate

The second parameter is your n value. The third and following parameters are the range specification for the loops.

I Blocked a to prevent a global assignment to that symbol from breaking the function.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Faster than me ;) +1 – Rojo May 20 '13 at 04:12
  • @Rojo Well it only took me 6+ hours... :^) And I thought you were in bed? – Mr.Wizard May 20 '13 at 04:13
  • Haha, I just came back home, was about to go to bed, saw the other question, commented, and when I was about to lie down, it was stronger than me to come and answer. Then I saw this one, started to type Do[ and your answer appeared – Rojo May 20 '13 at 04:22
  • 5
    @rojo I'd love that sort of auto-completion - start typing, and Mr Wizard fills the rest in for me...! – cormullion May 20 '13 at 06:32
1

Say for $n=1$, you have defined f[{i1}] as your first experiment. For $n=2$, your experiments are defined by f[{i1,i2}], for $n=3$ the experiments are defined by f[{i1,i2,i3}] and etc, with the idea that you wish to allow $n$ such experiments. If you structure your experiments this way, then you can create a list of all experiments by

m = 3; n = 3; c = Tuples[Range[m], n]

Here $m$ is the number of values each variable is to take on, and $n$ is how many variables you have. Now you can run all your experiments at once using

Map[f, c]

or use the shortcut

f /@ c

For $m=n=3$, this gives

{f[{1, 1, 1}], f[{1, 1, 2}], f[{1, 1, 3}], f[{1, 2, 1}], f[{1, 2, 2}],
 f[{1, 2, 3}], f[{1, 3, 1}], f[{1, 3, 2}], f[{1, 3, 3}], 
 f[{2, 1, 1}], f[{2, 1, 2}], f[{2, 1, 3}], f[{2, 2, 1}], f[{2, 2, 2}],
 f[{2, 2, 3}], f[{2, 3, 1}], f[{2, 3, 2}], f[{2, 3, 3}], 
 f[{3, 1, 1}], f[{3, 1, 2}], f[{3, 1, 3}], f[{3, 2, 1}], f[{3, 2, 2}],
 f[{3, 2, 3}], f[{3, 3, 1}], f[{3, 3, 2}], f[{3, 3, 3}]}

so you can see all 3^3 experiments will run. In general you will have $n^m$ experiments. As Mr. Wizard suggests, an alternative to Map would be to use Scan:

Scan[Print[f[#]] &, c]

This might be preferred if your experiment function f has "side effects", such as making assignments, or generating output, since Scan will suppress these.

bill s
  • 68,936
  • 4
  • 101
  • 191
  • I thought about posting something like this but held off because I thought Do might be specified because of memory restrictions. Nevertheless the packed array from Tuples is compact, and this should be practical for a large range of applications. I would however mention Scan as that is more analogous to Do. +1 – Mr.Wizard May 20 '13 at 05:25
  • Mr. Wizard -- Yes, I agree I was taking some liberties with the question: but this is one of the things with functional programming - if you plan ahead and build your "experiments" correctly, then later steps (like this one) become almost trivial. In fact, I would say planning ahead is important in any kind of programming. – bill s May 20 '13 at 05:29