重新定义Mathematica中的下标

时间:2011-03-15 11:00:30

标签: wolfram-mathematica pattern-matching variable-assignment

我想重新定义Subscript,以便将“二叉树坐标”转换为“平面阵列坐标”:

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]

我期望得到的是.3, .5。相反,我得到Set::write : Tag Subscript in {.1, .2, .3}_1,1 is Protected并且未分配值。请指教。

1 个答案:

答案 0 :(得分:6)

这是概念上最简单的解决方案 - 您添加一个新的“Up”规则来处理分配:

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]

您需要一个单独的规则来处理分配(Set=),否则当您执行Subscript[y, 1, 1] = .5

时,您将尝试分配给下标表达式

虽然上面的解决方案可以按字面意思使用,但它可能不应该,因为它为所有类型的第一个参数重新定义Subscript。这种重新定义可能不安全 - 它们可能会与Subscript的其他可能需要的用途发生冲突。例如,在某个任意符号x上调用Subscript会导致错误消息和我们可能不需要的评估:

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]]

更安全的替代方法是为要重新定义Subscript的二叉树分配一些特殊头(如标记),并使用模式相应地限制这些重定义的范围。以下是它的外观:

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];

您可以将btree结构分配给变量,如下所示:

In[156]:= y = btree[{.1, .2, .3}]

Out[156]= btree[{0.1, 0.2, 0.3}]

然后,

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]

通过这种方式,我们可以减少此类重新定义可能对其他代码(系统的其余部分)产生的不必要影响。

回顾涉及Set的定义,需要注意的一点是我们不能使用像Set[Subscript[x_btree, i_Integer, j_Integer],v_]:=...这样的简单模式,因为变量(y这里)还没有当模式匹配时,评估为Set内的值,因此它将不匹配。使用Condition/;)只是将我们分配的变量从Set中提取出来的一种方法,并使其得到评估。因此,如果它是y,那么Head[y]将导致y进行评估 - 这就是我们实际需要评估表达式的头部的情况。在像x_btree这样的模式中,我们不会在模式匹配尝试发生之前给x一个机会进行评估,因此模式不匹配(因为它仍然是一个符号y那里)。

此处使用的附加规则称为UpValue。要创建此类规则,请使用特殊语法(^:=运算符 - UpSetDelayed,这是创建UpValues的一种方法)。 UpValues是“软”重载函数(包括系统函数)的重要机制,也是自定义数据类型的创建。要了解它们,一个很好的起点是here