9
$\begingroup$

I have the following code:

Subscript[f, i_][x_] := Block[{a},
  Subscript[a, i] = 3 x;
  Subscript[a, 1]
]

If I evaluate for example Subscript[f,1][2], it evaluates to 6. After that asking what Subscript[a,1] is also gives me six. However, I want a to be a local variable.

My question: how can I define a local variable while using indices...?

Note: the original post mentioned that evaluating Subscript[f,1][2] = 6 would lead to the described behaviour, which just isn't true. A reasonable guess is that this was ment to mean that Subscript[f,1][2] was to be evaluated and it would evaluate to 6 (which it does). After that Subscript[a,1] will evaluate to 6 as reported.

$\endgroup$
4
  • $\begingroup$ Hello Bee, and welcome to math.SE. I think your question is better suited to the mathematica.SE site, so I'm going to migrate it there. There will be a link that appears below the question here that you can follow to the new location of your question. If you need help associating an account on mathematica.SE, you can flag your question for moderator attention, and someone over there will help out. $\endgroup$ Commented Apr 5, 2012 at 15:29
  • $\begingroup$ I can't seem to reproduce this. Does this behave this way on a fresh Mathematica session? $\endgroup$
    – rcollyer
    Commented Apr 5, 2012 at 15:39
  • $\begingroup$ @Bee: are you following this and the discussion to one of the answers? I'd suggest you have a look at my edit to your question and see if you think this makes sense. $\endgroup$ Commented Apr 5, 2012 at 16:44
  • $\begingroup$ @AlbertRetey Bee is unregistered on Mathematics, and not at all here. So, it is likely that she is not following this. Do as you will, then. $\endgroup$
    – rcollyer
    Commented Apr 5, 2012 at 16:51

3 Answers 3

8
$\begingroup$

The problem is that the definition which makes Subscript[a,i] evaluate to 6 is stored in the DownValues of Subscript. The down values of Subscript don't care about the blocking of a and will still exist when Block exits. You can check that by evaluating DownValues[Subscript]. You could use TagSet (shortcut: /:) to store that value in the UpValues of the localized a, which would behave as you expect (i.e. the rule in UpValues of a is removed when Block exits):

ClearAll[f, a, Subscript]
Subscript[f, i_][x_] := Block[{a},
  a /: Subscript[a, i] = 3 x;
  Subscript[a, 1]
]

on the other hand I wouldn't actually recommend to use such subscripted variables, what you have seen is probably only one of several unexpected things that could happen.

Side Note:It probably should be mentioned that the definition for Subscript[f,i_][x_] is also not associated with f but with Subscript, which can be checked by evaluating SubValues[Subscript]. Unfortunately this can not be changed by using TagSet for f, since Mathematica here will complain about f being too deep in the left hand side expression. One possibility to change that is to reformulate the function definition to e.g.:

f /: Subscript[f, i_] = Function[x,
  Block[{a},
   a /: Subscript[a, i] = 3 x;
   Subscript[a, 1]
   ]
  ]

which will behave the same as the original in most practical cases but of course is not exactly the same thing. You can use UpValues[f] to check that this rule is now really associated with f.

$\endgroup$
5
  • $\begingroup$ Actually, DownValues[Subscript] does not show anything, however SubValues[Subscript] does. $\endgroup$
    – rcollyer
    Commented Apr 5, 2012 at 16:39
  • $\begingroup$ I think that depends on whether one evaluates Subscript[f,1][2] or Subscript[f,1][2]=6, as discussed elswhere... $\endgroup$ Commented Apr 5, 2012 at 16:54
  • $\begingroup$ Ah, I see. Then the answer needs to be clarified slightly, as there are no DownValues of Subscript associated with f (which is what I think you're answer implies) only SubValues, but there DownValues associated with a. $\endgroup$
    – rcollyer
    Commented Apr 5, 2012 at 17:06
  • 1
    $\begingroup$ @rcollyer: I just added some additional remarks about downvalues, upvalues and subvalues. Hope this is now somewhat clearer. $\endgroup$ Commented Apr 6, 2012 at 13:26
  • $\begingroup$ You already had my +1, but thanks. $\endgroup$
    – rcollyer
    Commented Apr 6, 2012 at 14:05
5
$\begingroup$

I think you want to use Module[] instead of Block[]

Subscript[f, i_][x_] := Module[{a}, Subscript[a, i] = 3 x; Subscript[a, 1]]
$\endgroup$
10
  • $\begingroup$ Absolutely, but can you get the behavior with Subscript[a,1] that the OP is observing? $\endgroup$
    – rcollyer
    Commented Apr 5, 2012 at 15:42
  • $\begingroup$ @rcollyer: Yes of course, it's even what I would expect :-). What are you observing and why would you think it should be different from what the OP writes? $\endgroup$ Commented Apr 5, 2012 at 15:48
  • $\begingroup$ Yes, if I post the OP's code into a fresh MMA session, I reproduce his issue, Subscript[a,1] returns 6 after an evaluation of Subscript[f,1][2]. However, changing Block[] to Module[], restarting the kernal and running the notebook again yields the desired behavior, namely Subscript[f,1][2] = 6 and Subscript[a,1] = Subscript[a,1] $\endgroup$ Commented Apr 5, 2012 at 15:48
  • 1
    $\begingroup$ @johntfoster: while that in a sense behaves like the OP wants, you would accumulate one rule per call to Subscript[f,_][_] in the downvalues of Subscript (evaluate DownValues[Subscript] to see what I'm talking about). This might not be a problem but could well become one when the function gets called frequently. Also there might be reasons to use Block instead of Module, they serve different purposes... $\endgroup$ Commented Apr 5, 2012 at 15:52
  • 1
    $\begingroup$ @rcollyer: I have now edited the question and made a note about that change. $\endgroup$ Commented Apr 5, 2012 at 16:43
4
$\begingroup$

As Albert Retey says, the issue is that

Subscript[a, i] = 3 x

affects the DownValues of Subscript, not any of the values of a. Subscript is one of the few system-defined symbols where you can modify its values without unprotecting it first (Derivative is another). Thus, in order to localize changes to subscripts of a, you need to use Block on Subscript instead of a. Thus, for your simple use case, you can do:

Subscript[h, i_][x_] := Block[{Subscript},
  Subscript[b, i] = 3 x;
  Subscript[b, i]]

Now things work as you want:

In[17]:= Subscript[h, 4][3]
Out[17]= 9

In[18]:= Subscript[b, 3]
Out[18]= Subscript[b, 3]

This has the drawback that you lose , because you lose all access to values of Subscript from outside the Block. For a somewhat contrived example of what can go wrong, consider:

Subscript[c, 1] = 17;

Subscript[hh, i_][x_] := Block[{Subscript},
  Subscript[b, i] = If[OddQ@Subscript[c, 1], 3 x, 4 x];
  Subscript[b, i]]

In[23]:= Subscript[hh, 4][17]
Out[23]= 68

In[24]:= OddQ@Subscript[c, 1]
Out[24]= True

This is perhaps not what you wanted to have happen. Now you can go ahead and manipulate things so that Subscript gets all the DownValues and SubValues from outside the Block, but this is an error-prone and likely inefficient hassle. However, there's an internal function that does exactly what you would want in this case, called InternalInheritedBlock`:

Subscript[hhh, i_][x_] := Internal`InheritedBlock[{Subscript},
  Subscript[b, i] = If[OddQ@Subscript[c, 1], 3 x, 4 x];
  Subscript[b, i]]

Now you get the subscripts you want from outside without having to worry about clobbering anything:

In[31]:= Subscript[hhh, 4][17]
Out[31]= 51

In[32]:= Subscript[b, 3]
Out[32]= Subscript[b, 3]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.