Mathematica: переопределение свойства Listable для Plus - PullRequest
4 голосов
/ 06 января 2011

Я хотел бы определить символ pt для хранения точки (и, в конечном итоге, кешировать некоторые данные, связанные с этой точкой):

pt::"usage" = "pt[{x,y}] represents a point at {x,y}";

Я хотел бы иметь возможность использовать такие pt объекты в качестве точек как можно больше способов, в частности, я хотел бы иметь возможность написать

{a0,a1}+pt[{b0,b1}]

и вернуть pt[{a0+b0,a1+b1}] вместо {a0+pt[{b0,b1}],a1+pt[{b0,b1}]}. Моя оригинальная идея заключалась в использовании:

pt /: Plus[pt[p0_], p1 : {_, _}] = pt[p0 + p1];

Но это не работает (потому что Plus - это Listable?). Есть ли способ сделать это без снятия защиты Plus?

Обновление: Как указывает Леонид, это невозможно без глобального или локального взлома Plus, поскольку атрибут Listable рассматривается перед любыми * значениями. Это очень точно описано в учебном пособии .

Ответы [ 2 ]

6 голосов
/ 06 января 2011

Оценщик Mathematica кажется недостаточно гибким, чтобы сделать это легко. UpValues ​​для pt действительно применяются до DownValues ​​для Plus, но многопоточность списков из-за Lisability происходит еще до этого. В данном конкретном случае вам могут помочь:

eval = Function[code,Block[{Plus = Plus, attr = DeleteCases[Attributes[Plus], Listable]},
SetAttributes[Plus, attr]; code], HoldAll]

Чтобы использовать его, оберните его вокруг фрагмента кода, где вы хотите применить правило для pt, например:

eval[{a0, a1} + pt[{b0, b1}]]

Вы можете использовать $ Pre как $Pre = eval, чтобы не вводить eval каждый раз, хотя обычно я бы не рекомендовал это. Blocking Plus - более мягкий способ временно отключить некоторые или все его атрибуты. Преимущество w.r.t. очистка и установка атрибутов без блокировки означает, что вы не можете оказаться в глобальном состоянии с постоянно отключенным атрибутом Listable, даже если выброшено исключение или вычисление отменено.

Поскольку атрибут Listable напрямую влияет на оценку, а не на сопоставление с шаблоном (последний, конечно, может быть затронут косвенно, если какой-либо шаблон должен соответствовать результату Plus, добавленному в список по списку), в большинстве случаев это будет нормально Теоретически, это может все же привести к некоторым нежелательным эффектам в некоторых случаях, особенно когда происходит сопоставление с образцом. Но на практике это может быть достаточно хорошо. Более чистым, но более сложным решением было бы создание собственного оценщика с учетом ваших потребностей.

1 голос
/ 07 января 2011

Следующее является немного расточительным, но оно работает: Идея состоит в том, чтобы просто отслеживать случаи, когда атрибут Listable в Plus поместил одинаковый pt во все элементы списка (т.е. необработанную точку ) - а затем вытащите его обратно. Сначала определим функцию для добавления объектов pt:

SetAttributes[ptPlus, {Orderless}]
ptPlus[pt[pa : {_, _}], pt[pb : {_, _}], r___] := 
  ptPlus[pt[pa + pb], r];
ptPlus[p_pt] := p; 

Затем мы удостоверяемся, что любой Plus, который включает pt, сопоставлен с ptPlus (связывает правило с pt).

Plus[h___, a_pt, t___] ^:= ptPlus[h, a, t];

Вышеуказанные правила означают, что: {x0,y0}+pt[{x1,y1}] будет расширен с {x0+pt[{x1,y1}],y0+pt[{x1,y1}]} до {ptPlus[x0,pt[{x1,y1}]],ptPlus[y0,pt[{x1,y1}]]}. Теперь мы просто создаем правило для преобразования этого в pt[{x0,y0}]+pt[{x1,y1}] (обратите внимание на отложенное условие, которое проверяет, что pt s равны):

{ptPlus[x__], ptPlus[y__]} ^:= Module[{
    ptCases = Cases[{{x}, {y}}, _pt, {2}]},
  ptCases[[1]] + pt[Plus @@@ DeleteCases[{{x}, {y}}, _pt, {2}]] 
    /; Equal @@ ptCases]

Более непрозрачный, но немного более осторожный вариант, который легче обобщить на более высокие измерения:

ptPlus /: p : {_ptPlus, _ptPlus} := Module[{ptCases, rest,
   lp = ReleaseHold@Apply[List, Hold[p], {2}]},
  ptCases = Cases[lp, _pt, {2}];
  rest = Plus @@@ DeleteCases[lp, _pt, {2}];
  ptCases[[1]] + pt[rest] /; And[Equal @@ ptCases, VectorQ@rest]]

Весь этот подход, конечно, приведет к ужасно тонким ошибкам, когда {a+pt[{0,0}],a+pt[{0,b}]} /. {a -> pt[{0,0}]} оценивается как pt[{0,0}], когда c==0 и {pt[{0,0}],pt[{0,c}]} в противном случае ...

HTH - сказал парень про себя ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...