Переопределить индекс в Mathematica - PullRequest
4 голосов
/ 15 марта 2011

Я бы хотел переопределить 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 Ответ

6 голосов
/ 15 марта 2011

Вот концептуально простое решение - вы добавляете новое правило «Вверх» для обработки назначения:

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 при выполнении Subscript[y, 1, 1] = .5

Хотя вышеприведенное решение может * буквально использоваться , оно, вероятно, не должно использоваться, поскольку оно переопределяет Subscriptдля всех типов первого аргумента.Такие переопределения могут быть небезопасными - они могут вступать в противоречие с другими, возможно желательными видами использования SubscriptНапример, вызов Subscript для некоторого произвольного символа x приводит к сообщению об ошибке и оценке, которая может нам не понадобиться:

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 - важный механизм для «мягкой» перегрузки функций (включая системные функции), а также создания пользовательских типов данных.Чтобы прочитать о них, хорошей отправной точкой является здесь .

...