开发者

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 SubscriptBoxs have been converted to the input form Subscripts. 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

Subscripted variables


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 Subscripts 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[ ] ).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜