Subscripted variables
Is there any way to force Mathematica to treat subscripted variables independently of their unsubscripted counterparts? More specifical开发者_如何学JAVAly. Say, I have the following definitions:
Subscript[b, 1] = {{1, 2}}
Subscript[b, 2] = {{3, 4}}
b = Join[Subscript[b, 1], Subscript[b, 2]]
Now when I use
Subscript[b, 1]
Mathematica will substitute it with
Subscript[{{1, 2}, {3, 4}},1]
when I want these to be three independent values, so changing b will not affect Subscript[b, ..]. Is it possible?
In an answer to a previous SO question, Mathematica Notation and syntax mods, telefunkenvf14 mentioned that he was
hoping to use Notations to force MMA to treat subscripted variables as a symbol
which is essentially what this question is about.
WReach pointed out that the Notation package can do this quite simply using Symbolize
Needs["Notation`"];
Symbolize[ParsedBoxWrapper[SubscriptBox["_", "_"]]]
Where (as in Daniel's answer) don't worry too much about the Box
structure above as you can use the Notation
palette to enter this stuff in more simply.
Check that it all works as wanted:
In[3]:= Subscript[a, b]//Head
a = 1
Subscript[a, b]
Out[3]= Symbol
Out[4]= 1
Out[5]= Subscript[a, b]
and
In[6]:= Subscript[b, 1] = {{1, 2}}
Subscript[b, 2] = {{3, 4}}
b = Join[Subscript[b, 1], Subscript[b, 2]]
Out[6]= {{1, 2}}
Out[7]= {{3, 4}}
Out[8]= {{1, 2}, {3, 4}}
Note: all of the above code has been copied as Input Text, so the typeset SubscriptBox
s have been converted to the input form Subscript
s. However, the Symbolize
works at the box level, so the tests need to be converted back to their 2d forms. To do this, select the code (or cells) and convert it to standard form by using the Cell
menu or the shortcut Ctrl-Shift-N
. The notebook with all the above code should look like
If you don't want to use the Notation
package (see Daniel's and my answers) but want to copy the behaviour of Symbolize
, then it gets a little tricky.
I had a go at doing this after I reading this SO answer but ran into troubles and gave up. I'll put the code here as community wiki so other people can try to finish it!
First you want to intercept an inputted subscript box structure and make it be interpreted as a "unique" symbol. The following code
MakeExpression[SubscriptBox[x_String, i_String], form_] :=
With[{name = StringJoin[{"$sUbsCript$", x, "$SPLIT$", i}]},
Hold[Symbol[name]]]
makes an inputted x_i
become a symbol named "$sUbsCript$x$SPLIT$i"
. Not a guaranteed unique symbol name... but it would a fairly unusual one!
Notes:
1) that this code will not pick up subscripts written in FullForm
.
2) this definition only fires off if both parts of the subscript are "simple" - no spaces, brackets, operators, etc...
Next, because this symbol name is so ugly, here's an optional something to make it nicer when it's asked for (this probably should be changed)
Protect[$inSymbolName];
Unprotect[SymbolName];
SymbolName[symb_Symbol] :=
Block[{$inSymbolName = True, result, s},
result = If[StringMatchQ[s = SymbolName[symb], "$sUbsCript$" ~~ __],
StringJoin@StringSplit[StringDrop[s, 11], "$SPLIT$"],
s]] /; ! TrueQ[$inSymbolName]
Protect[SymbolName];
Finally, we want this subscript symbol to print out nicely. Normally we'd do this using a MakeBoxes
definition -- but we can't in this case because Symbol
has the attribute Locked
:(
Instead, we'll hack in a $PrePrint
to find these crazily named symbols and write them back as subscripts:
$PrePrint = (# /. s_Symbol :>
Block[{$inSymbolName = True},
If[StringMatchQ[SymbolName[s], "$sUbsCript$" ~~ __],
Subscript@@StringSplit[StringDrop[SymbolName[s], 11], "$SPLIT$"], s]]
)&;
Finally the place where all of this falls down is if you try to assign something to a subscripted symbol. I haven't tried working around this yet!
Some tests - note that you'll have to convert the Subscript
s to actual boxes for the code to work. Do this by converting to StandardForm: Ctrl-Shift-N.
symbs = {x, yy, Subscript[a, 3], Subscript[long, name]};
In[10]:= Head/@symbs
Out[10]= {Symbol, Symbol, Symbol, Symbol}
In[11]:= SymbolName/@symbs
Out[11]= {x, yy, a3, longname}
In[12]:= Block[{$inSymbolName=True},SymbolName/@symbs]
Out[12]= {x, yy, $sUbsCript$a$SPLIT$3, $sUbsCript$long$SPLIT$name}
In[13]:= f[x_Symbol] := Characters[SymbolName[x]]
In[14]:= {f["acb"], f[abc], f[Subscript[xx, 2]]}
Out[14]= {f["acb"], {"a", "b", "c"}, {"x", "x", "2"}}
It doesn't work with Set
or SetDelayed
if they generate OwnValues
and it doesn't work with Information
In[15]:= Subscript[x, y] = 5
??Subscript[x, y]
During evaluation of In[4]:= Set::write: Tag Symbol in Symbol[$sUbsCript$x$SPLIT$y] is Protected. >>
Out[15]= 5
During evaluation of In[4]:= Information::nomatch: No symbol matching Symbol["$sUbsCript$x$SPLIT$y"] found. >>
It does work with definitions that produce DownValues
In[17]:= Subscript[x, z][z_]:=z^2
In[18]:= Subscript[x, z][2]
Out[18]= 4
In[19]:= ?Subscript[x, z]
Information::nomatch: No symbol matching Symbol["$sUbsCript$x$SPLIT$z"] found. >>
Here's some code I used to use to do this. It should work for you too:
SubscriptToProxySymbol[_] = Null;
MakeExpression[SubscriptBox[a_, b_], StandardForm] :=
Module[{proxy, boxes = SubscriptBox[a, b]},
proxy = SubscriptToProxySymbol[boxes];
If[proxy === Null, proxy = ToString[Unique[ProxySymbol]];
SubscriptToProxySymbol[boxes] = proxy;
With[{n = Symbol[proxy]}, MakeBoxes[n, StandardForm] := boxes];];
MakeExpression[RowBox[{proxy}], StandardForm]]
With this, definitions like
f[Subscript[a, b] : _] := Sin[Subscript[a, b]]
are internally stored like this:
In[11]:= InputForm@DownValues[f]
Out[11]//InputForm=
{HoldPattern[f[ProxySymbol$99_]] :> Sin[ProxySymbol$99]}
But they display as subscripts.
From a quick look I think this may be what Simon was aiming for.
If your application allows it, you may wish to consider adopting Mathematica-like naming conventions such as FullyDescriptiveCamelCase variable names instead of subscripted variables. It will make your code more portable in the end, and it does become second nature eventually.
Could use Notation from the package of same name.
Don't mind the code below, you don't figure out that RowBox structure. Just use the palette template and type Subscript[b,j_] into the left side, and, say, bb[j_], into the right. So the "actual"variables are now bb[1] etc., and you can assign safely to b.
Needs["Notation`"]
Notation[ParsedBoxWrapper[
RowBox[{"Subscript", "[",
RowBox[{"b", ",", "j_"}], "]"}]] \[DoubleLongRightArrow]
ParsedBoxWrapper[
RowBox[{"bb", "[", "j_", "]"}]]]
Subscript[b, 1] = {{1, 2}}
Subscript[b, 2] = {{3, 4}}
b = Join[Subscript[b, 1], Subscript[b, 2]]
Out[3]= {{1, 2}}
Out[4]= {{3, 4}}
Out[5]= {{1, 2}, {3, 4}}
Subscript[b, 1]
Out[6]= {{1, 2}}
You'll probably get more accurate replies, this is the first I ever mucked with the Notation package.
Daniel Lichtblau Wolfram Research
The symbol is b
, and not Subscript[b, _]
.
When you define:
Subscript[b, 1] = {{1, 2}}
is like defining a downvalue for any function f. Like doing:
f[b, 2] = {{1, 2}}
So, what you are doing is
f[b, 1] = {{1, 2}}
f[b, 2] = {{3, 4}}
b = Join[f[b, 1], f[b, 2]]
Which of course assigns a value to the symbol b.
and now
f[b, 1]
->f[{{1, 2}, {3, 4}}, 1]
As expected.
So, I guess the short answer is no. At least not in a straightforward way.
Edit
While the above is true (I believe), I wasn't aware that the Notation package has a way to circumvent the default behavior. Other answers contain the details.
I studied the thread on subscripted variables in detail by pasting the various replies into a Mathematica notebook (and tried it with version 7 and 8). However, what I found out that in some cases the explicit representation of subscripted variables as Subscript[a,b]
does not give the correct answer as contained in these answers. However, when I used explicitly the 2d notation for subscript ( a_b ) the answer was as expected. Could it be that when pasting subscripted symbols into an email they are represented as
Subscript[a,b]
. (Of course, I should add that for each individual contributions I started Mathematica fresh - after using Quit[ ]
).
精彩评论