10

Is there any way to force Mathematica to treat subscripted variables independently of their unsubscripted counterparts? More specifically. 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?

Max
  • 19,654
  • 13
  • 84
  • 122

6 Answers6

13

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 screenshot

Community
  • 1
  • 1
Simon
  • 14,631
  • 4
  • 41
  • 101
2

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. >>
Community
  • 1
  • 1
Simon
  • 14,631
  • 4
  • 41
  • 101
2

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.

Andrew Moylan
  • 2,893
  • 18
  • 20
1

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.

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
  • Of course, I wonder what internal magic the Notation package actually uses to achieve what it does? For example what does `Symbolize` actually do? – Simon Mar 30 '11 at 07:20
  • @Simon ha! I posted and then deleted a similar comment on your answer. That kind of things makes me shudder :) – Dr. belisarius Mar 30 '11 at 07:24
  • It wouldn't be so bad - except that `Symbol` is `Locked` - which prevents you from giving it extra `MakeBoxes` definitions. See the [Community Wiki "answer"](http://stackoverflow.com/questions/5481216/subscripted-variables/5481897#5481897) I posted below. – Simon Mar 30 '11 at 07:31
  • 1
    @Simon I think your answer is a very nice one, but I doubt about the robustness of the whole thing. When you want a calc done Mma is great, but the environment per se looks fragile, and the debug process (hard on its own) is usually more difficult each time you add a level of abstraction/redefinition. – Dr. belisarius Mar 30 '11 at 07:46
  • The answer has serious problems - I only put it up so that other people can procrastinate by fixing it for me! – Simon Mar 30 '11 at 08:18
1

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

Daniel Lichtblau
  • 6,854
  • 1
  • 23
  • 30
  • @Daniel As it should be obvious from my answer, I never did. :) – Dr. belisarius Mar 30 '11 at 03:22
  • Hi Daniel: The Notation package has a command called `Symbolize` that is designed to do what Max wanted. The full `Notation` command is not needed. – Simon Mar 30 '11 at 04:02
  • 4
    Potential issue with custom notation is that parsing mechanism for .nb and .m files is different. It definitely causes a problem for InfixNotation (https://groups.google.com/forum/#!msg/comp.soft-sys.math.mathematica/wABDm0h1EHg/CHHrGkdfbcIJ), not sure about Symbolize – Yaroslav Bulatov Mar 30 '11 at 06:16
  • @Daniel I'm puzzled by your answer. If you input `Subscript[b,1]` you will indeed get `{{1,2}}` as output. But if you enter the same thing formatted as a subscript, ie. b+Control[-], you will obtain a nicely rendered result of `Subscript[{{1,2},{3,4}},1]` in return. – DavidC Mar 30 '11 at 10:03
  • @David: Try using the command `Notation[ParsedBoxWrapper[\(b\_j_\)] \[DoubleLongLeftRightArrow] ParsedBoxWrapper[\(bb[j_]\)]]`. – Simon Mar 30 '11 at 10:42
  • @David It works for me, as long as you don't mix Subscript[b,1] and b_1 (_ indicating subscripting). So, b_1 = {{1, 2}}; b_2 = {{3, 4}} b = Join[b_1, b_2] works, but b_1 = {{1, 2}}; b_2 = {{3, 4}} b = Join[Subscript[b, 1], Subscript[b, 2]] (on a clean kernel) yields b[1, 2] – Sjoerd C. de Vries Mar 30 '11 at 10:55
  • @Simon Thanks, it works. Now I'll try to figure out why. I'll be reflecting on your code and Sjoerd's. – DavidC Mar 30 '11 at 13:35
0

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

Simon
  • 14,631
  • 4
  • 41
  • 101
  • 1
    Hi Robert, welcome to Stack Overflow. Posting a new answer is not really the place for such a comment, but since you don't have enough [reputation to comment](http://stackoverflow.com/privileges/comment), I guess there's not much else you could do to raise this valid point. Mathematica automatically converts the subscript boxes to full form when copying as input text, I think that everyone automatically converted the full form back to boxes when testing and no-one thought of mentioning this fact. I'll update my answer to reflect this concern. – Simon Aug 15 '11 at 11:50