开发者

Redefine Subscript in Mathematica

I'd like to redefine Subscript such that the "binomial tree coordinates" are translated into "flat array coordinates":

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 get is .3, .5. Instead I get Set::write : Tag Subscript in {.1, .2, .3}_1,1 is Protected and the value is not assigned. Please advise.


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

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 handling assignments (Set, =), otherwise you are attempting to assign to the Subscript expression itself when you do Subscript[y, 1, 1] = .5

While the above solution can be used literally, it probably should not, since it redefines Subscript for all types of the first argument. Such redefinitions may be unsafe - they may clash with other possibly desirable uses of Subscript. For example, calling Subscript on some arbitrary symbol x results in an error-message, and evaluation which we may not 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 (like a tag) for the binary trees on which you want to redefine Subscript, and use patterns to restrict the scope of these redefinitions accordingly. Here is how it might look:

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 you btree structure to the variable like this:

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]

In this way, we reduce the possible unwanted effects that such redefinitions can have on some other code (rest of the system).

Looking back at the definition involving Set, one thing to note is that we could not have used a simple pattern like Set[Subscript[x_btree, i_Integer, j_Integer],v_]:=..., since the variable (y here) would not yet evaluate to a value inside Set when the pattern is matched, so it won't match. Using Condition (/;) is just one way to bring the variable we are assigning to, out of Set, and make it evaluate. So, if it is y, then Head[y] will cause y to evaluate - this is the case where we actually want the head of the evaluated expression. In pattern like x_btree, we don't give x a chance to evaluate before the pattern-matching attempt takes place, and therefore the pattern does not match (since it is still a symbol y there).

The additional rule used here is called an UpValue. To create such rules, a special syntax is used (^:= operator - UpSetDelayed, is one way to create UpValues). UpValues are an important mechanism for "soft" overloading of functions (including system functions), and also creation of custom data types. To read about them, a good starting point is here.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜