Override Subscript Number in Mathematica

I would like to redefine Subscript so that the "binomial tree coordinates" are translated into "coordinates of flat arrays":

 Unprotect[Subscript]; Subscript[x_, i_, j_] := x[[2 ^ i + j]]; Protect[Subscript]; (* Binomial Tree *) y = {.1, {.2, .3}} // Flatten; Subscript[y, 1, 1] Subscript[y, 1, 1] = .5; Subscript[y, 1, 1] 

What I expect to receive is .3, .5 . Instead, I get Set::write : Tag Subscript in {.1, .2, .3}_1,1 is Protected , and no value is assigned. Please inform.

+4
source share
1 answer

Here is the conceptually simplest solution - you add a new "Up" rule to process the task:

 Unprotect[Subscript]; Subscript[x_, i_, j_] := x[[2^i + j]] Set[Subscript[x_, i_, j_], v_] ^:= x[[2^i + j]] = v; Protect[Subscript]; (*Binomial Tree*) y = {.1, {.2, .3}} // Flatten Subscript[y, 1, 1] Subscript[y, 1, 1] = .5; Subscript[y, 1, 1] 

You need a separate rule for processing assignments ( Set , = ), otherwise you are trying to assign substrings to the expression itself when you do Subscript[y, 1, 1] = .5

While the above solution can be used literally, it probably shouldn't, since it overrides Subscript for all types of the first argument. Such overrides may be unsafe - they may interfere with other, possibly desirable, subscript applications. For example, calling a subheading on some arbitrary character x leads to an error message and an estimate that we cannot want:

 In[137]:= Subscript[x, 1, 2] During evaluation of In[137]:= Part::partd: Part specification x[[4]] is longer than depth of object. >> Out[137]= x[[4]] 

A safer alternative would be to assign some special head (for example, a tag) for the binary trees on which you want to override Subscript , and use templates to limit the scope of these overrides accordingly. Here's what it looks like:

 Unprotect[btree, Subscript]; ClearAll[btree, Subscript]; Subscript[x_btree, i_, j_] := x[[1, 2^i + j]] Set[Subscript[x_, i_, j_], v_] ^:= (x[[1, 2^i + j]] = v) /; Head[x] === btree; Protect[btree, Subscript]; 

You assign the btree structure to the variable as follows:

 In[156]:= y = btree[{.1, .2, .3}] Out[156]= btree[{0.1, 0.2, 0.3}] 

Then

 In[157]:= Clear[x]; Subscript[y, 1, 1] Subscript[y, 1, 1] = .5; Subscript[y, 1, 1] Subscript[x, 1, 1] Out[158]= 0.3 Out[160]= 0.5 Out[161]= Subscript[x, 1, 1] 

Thus, we reduce the possible unwanted effects that such overrides may have for some other code (the rest of the system).

Looking back at the definition that includes Set , it should be noted that we could not use a simple template, for example, Set[Subscript[x_btree, i_Integer, j_Integer],v_]:=... since the variable ( y here) would not yet evaluate the value inside Set when the pattern is consistent, so it will not match. Using Condition ( /; ) is just one way to cast the variable we assign from Set and evaluate it. So, if it is y , then Head[y] will lead to the evaluation of y - this is the case when we really want the head of the evaluated expression. In a template like x_btree , we do not give x opportunity to evaluate before trying to match the template, and therefore the template will not match (since it is still the y character).

An additional rule used here is called UpValue . To create such rules, special syntax is used ( ^:= operator - UpSetDelayed , this is one way to create UpValues ). UpValues is an important mechanism for soft loading functions (including system functions), as well as creating custom data types. To read about them, a good starting point is here .

+6
source

Source: https://habr.com/ru/post/1343754/


All Articles