12
$\begingroup$

I recently lost a lot of time on this and need to understand whether I have misunderstood MMA operations or there's a problem. I am using MMA 10.1 on Windows 7 64-bit.

The essence of the issue is this: I believed that Table, RecurrenceTable etc, per the description of Table in the documentation, localise the iterating variable, and thus that using e.g. "i" in a RecurrenceTable and elsewhere in a notebook for some other purpose should not cause a conflict.

(Related question: ParametricPlot iterator not "block"-ed)

However as the three cases below show, unless the iterating variable is not reused or explicitly shielded by e.g. a Module in a definition incorporating a RecurrenceTable, I get the error that "1", "2", etc. cannot be used as a variable.

Sample code follows (with forced clear for safety). The first two definitions of logisticMap cause no problems in subsequent use, but when the subsequent use reuses an unshielded iterating variable the error occurs.

Clear[Evaluate[Context[] <> "*"]]

1st def: OK (i as a module variable in RecurrenceTable, and i in For[])

logisticMap[x0_, μ_, n_] := 
 Module[{i}, 
  RecurrenceTable[{x[i + 1] == μ x[i] (1 - x[i]), x[1] == x0}, 
   x, {i, 1, n}]]
pRow = {};
dataSeries := logisticMap[0.1, 3.55, 10];
For[i = 1, i <= 10, i++, AppendTo[pRow, dataSeries[[i]]]];

2nd def: OK (use b as iterator for RecurrenceTable and i in For[])

logisticMap[x0_, μ_, n_] := 
 RecurrenceTable[{x[b + 1] == μ x[b] (1 - x[b]), x[1] == x0}, 
  x, {b, 1, n}]
pRow = {};
dataSeries := logisticMap[0.1, 3.55, 10];
For[i = 1, i <= 10, i++, AppendTo[pRow, dataSeries[[i]]]];

3rd def: error (i as unshielded iterator in RecurrenceTable, and in For[])

logisticMap[x0_, μ_, n_] := 
 RecurrenceTable[{x[i + 1] == μ x[i] (1 - x[i]), x[1] == x0}, 
  x, {i, 1, n}]
pRow = {};
dataSeries := logisticMap[0.1, 3.55, 10];
For[i = 1, i <= 10, i++, AppendTo[pRow, dataSeries[[i]]]];

The error being

RecurrenceTable::dsvar: 1 cannot be used as a variable. >> etc.

a) What exactly is happening (why is "1" being used as a variable) and

b) Is this user error or a bug (that I would then report)?

[BTW Do you think Wolfram would respond +vely to a request for a free upgrade if this is a bug as this is a seriously undermining issue AND I am still suffering from an unresolved startup issue in 10.1?]

Thanks,

$\endgroup$
  • $\begingroup$ Simplest example: For[i = 1, i <= 5, i++]; Then look to see that i has value 6. $\endgroup$ – bill s Sep 19 '16 at 13:27
  • 2
    $\begingroup$ But For isn't really the issue here is it? This problem can be boiled down to the following, which produces the same error: i = 7; RecurrenceTable[{a[i + 1] == 3 a[i], a[1] == 7}, a, {i, 1, 3}] - Does the documentation say that RecurrenceTable does not localize its variable? $\endgroup$ – Jason B. Sep 19 '16 at 13:30
  • $\begingroup$ As an aside, using dataSeries = logisticMap[0.1, 3.55, 10] would make the 3rd block of code work. $\endgroup$ – Karsten 7. Sep 19 '16 at 13:30
  • $\begingroup$ I edited the title, because this is specific to RecurrenceTable - Table does scope its iteration variable. Notice the color of i in these two lines: Table[1, {i, 3}]; RecurrenceTable[1, a, {i, 4}] $\endgroup$ – Jason B. Sep 19 '16 at 13:34
  • $\begingroup$ Thanks; why on earth Table does scope its iteration variable and RecurrenceTable doesn't shall remain a mystery [Edit: I now see rationalisations below:)]. Now it's been pointed out by @JasonB I do see the colour difference, but it's still, to my mind nastily inconsistent, after all RecurrenceTable even has Table in its name! What other gotchas like this exist? Are they in a community wiki by any chance? $\endgroup$ – Julian Moore Sep 19 '16 at 15:12
13
$\begingroup$

As Bob Hanlon's answer points out, RecurrenceTable does not hold its arguments, but most especially, it does not hold its iterator arguments. This must surely be viewed as a bug as it departs completely from the iterator idiom established by Table, etc.

On the other hand, there is precedent for evaluating the iterator specifications. For example, Integrate:

Integrate[Sin[x], {x, 0, Pi}]
(* 2 *)

but

Module[{x = 1}
, Integrate[Sin[x], {x, 0, Pi}]
]

(* Integrate::ilim: Invalid integration variable or limit(s) in {1,0,\[Pi]}. *)

I would argue that this is a bug. But as Szabolcs notes in the comments, one could possibly argue that this behaviour is desirable in contexts that are heavily symbolic (e.g. mathematical expression manipulation). In any event, it is unlikely that long-standing mathematical functions like Integrate are going to be revised any time soon.

So to determine whether iterator evaluation for RecurrenceTable is a bug depends upon whether you think it is more like Table or Integrate.

Scoping

As to the necessity of localizing the iterator variable within the table expression itself, this is not a behavioural bug but rather a general idiom in Mathematica for functions that use iteration variables. Examples include Table, Sum, Plot, Do, For -- and RecurrenceTable. In all of these functions, the iteration variable is not fully localized. Its value is temporarily changed as if scoped using Block. See (94061) for a discussion of the consequences.

In most cases, the Details section of the documentation states this explicitly (see Table or Plot for example). RecurrenceTable does not make such an explicit statement, but it does obliquely mention that it acts similarly to Table. So perhaps we have a documentation bug here, but not a behavioural bug.

The canonical way to solve the scoping problem is to localize the iterator variable using Module as in the first example in the question. This, incidentally, also works around the premature evaluation of the iterator arguments.

$\endgroup$
  • $\begingroup$ It's clear why it's confusing, but there are arguments for why this isn't really "bad behaviour". RecurrenceTable is a function which is more mathematical than programming-focused in nature. Many such functions lack HoldAll, such as Integrate or NDSolve. One might argue that RecurrenceTable is to RSolve as NDSolve is to DSolve. $\endgroup$ – Szabolcs Sep 19 '16 at 14:34
  • $\begingroup$ I don't know why such functions tend not to be HoldAll, but we can try to make up reasons: such mathematical functions usually have formulas (and not code!) as their first argument. These formulas are often used outside of the function too, in the same session. It is thus not a good idea to give the variables used in these formulas any values. $\endgroup$ – Szabolcs Sep 19 '16 at 14:35
  • $\begingroup$ Yes, that similar to Table comment was unhelpful; see also comment to Bob Hanon's answer below. There might be reasons, but do they speak to necessity or sufficiency? Reasonable user expectations might be given greater emphasis perhaps if it's not necessary per se, but if it is, special attention should be drawn to the difference, IMHO. $\endgroup$ – Julian Moore Sep 19 '16 at 15:24
  • $\begingroup$ @Szabolcs I updated my answer to draw a clear distinction between the "expected" scoping behaviour and the manifest bug involving the unheld iterators identified by Bob Hanlon's answer. $\endgroup$ – WReach Sep 19 '16 at 15:39
11
$\begingroup$

Unlike many other functions that use an iterator, RecurrenceTable does not have the attribute HoldAll. Presumably, this indicates a different evaluation sequence (Evaluation in Iteration Functions).

Grid[
 Prepend[
  {#, Attributes[#]} & /@
   {Do, Product, Sum, Table, RecurrenceTable},
  Style[#, Bold] & /@ {"Function", "Attributes"}],
 Frame -> All]

enter image description here

$\endgroup$
  • $\begingroup$ Checked that ref to Evaluation in Iteration Functions; it's annoying to me as an inexperienced user that whilst Table goes out of its way to state that "Table effectively uses Block to localize values or variables." RecurrenceTable is silent on the matter; an explicit Does Not would have been visible to me and I might have worked it out - I do read the documentation but I haven't read it ALL! Ah well, c'est la via :) $\endgroup$ – Julian Moore Sep 19 '16 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.