Заменить все не работает, как ожидалось - PullRequest
4 голосов
/ 23 декабря 2010

Еще рано в Mathematica, поэтому, пожалуйста, прости, что, вероятно, очень очевидный вопрос Я пытаюсь создать несколько параметрических графиков. У меня есть:

ParametricPlot[{
    (a + b) Cos[t] - h Cos[(a + b)/b t],
    (a + b) Sin[t] - h Sin[(a + b)/b t]},
    {t, 0, 2 \[Pi]}, PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}

Нет радости: правила замены не применяются, а a, b и h остаются неопределенными.

Если я вместо этого сделаю:

Hold@ParametricPlot[{
    (a + b) Cos[t] - h Cos[(a + b)/b t],
    (a + b) Sin[t] - h Sin[(a + b)/b t]},
    {t, 0, 2 \[Pi]}, PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}

похоже, что работают правила, что подтверждается выводом:

Hold[ParametricPlot[{(2 + 1) Cos[t] - 
1 Cos[(2 + 1) t], (2 + 1) Sin[t] - 1 Sin[(2 + 1) t]}, {t, 0, 
2 \[Pi]}, PlotRange -> All]]

Что я и ожидал. Снимите Hold, и ParametricPlot не работает. Нет ничего плохого в уравнениях или самом ParametricPlot, потому что я попытался установить значения для a, b и h в отдельном выражении (a=2; b=1; h=1), и я вытащил свой довольно двойной кардоид, как и ожидалось.

Итак, что я делаю неправильно с ReplaceAll и почему правила преобразования не работают? Это еще один принципиально важный аспект ММА, который не понимает мой разрушенный ООП мозг.

Я попытался прочитать ReplaceAll и ParametricPlot, и ближайший ключ, который я обнаружил, заключался в том, что "ParametricPlot имеет атрибут HoldAll и оценивает f только после присвоения конкретных числовых значений переменным", что сильно помогу, иначе меня бы здесь не было.

Спасибо.

Ответы [ 4 ]

4 голосов
/ 23 декабря 2010

Mathematica оценивает каждую голову без атрибутов, сначала оценивая голову каждого подвыражения.Поскольку ReplaceAll не имеет атрибутов хранения, ParametricPlot становится Graphics перед заменой

Чтобы увидеть дерево выражений, выполните команду

ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - 
      h Sin[(a + b)/b t]}, {t, 0, 2 \[Pi]}, 
    PlotRange -> All] /. {a -> 2, b -> 1, h -> 1} // Hold // TreeForm

. Из этого дерева вы можете видеть, что ваша командато же самое, что и

temp1=ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - 
          h Sin[(a + b)/b t]}, {t, 0, 2 \[Pi]}, 
        PlotRange -> All]
temp2={a -> 2, b -> 1, h -> 1} 
temp1/.temp2

Посмотрите на FullForm[temp1], чтобы убедиться, что в этом выражении нет a или b.

Если вы установите ReplaceAll в HoldFirst, что препятствует оценке ParametricPlot до ReplaceAll, а результат соответствует ожидаемому.В этом случае ReplaceAll оценивается как выражение с головой ParametricPlot, и только в этой точке ParametricPlot оценивается.Обязательно верните атрибуты обратно, потому что изменение поведения встроенных команд может привести к неожиданным побочным эффектам.

SetAttributes[ReplaceAll, HoldFirst]; 
ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - 
    h Sin[(a + b)/b t]}, {t, 0, 2 \[Pi]}, 
  PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}
ClearAttributes[ReplaceAll, HoldFirst]

Полезный прием при оценке аргументов, передаваемых в функцию с HoldAll, - выполнение операций.в выражении с List head и в конце подставьте ParametricPlot, например

ParametricPlot @@ ({{(a + b) Cos[t] - 
      h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]}, {t, 0,
      2 \[Pi]}, PlotRange -> All} /. {a -> 2, b -> 1, h -> 1})
3 голосов
/ 23 декабря 2010

Именно так ReplaceAll всегда работает.

См. Например:

In[10]:= (a/a) /. a -> 0

Out[10]= 1  

Очевидно, что замена выполняется ПОСЛЕ оценки, потому что если вы выполните:

In[11]:= a = 0; a/a

During evaluation of In[11]:= Power::infy: Infinite expression 1/0 encountered. >>

During evaluation of In[11]:= Infinity::indet: Indeterminate expression 0 ComplexInfinity encountered. >>

Out[12]= Indeterminate  

Теперь, вопрос вставкизамена на том уровне, на котором вы хотите, чтобы он работал.Поскольку результатом графика в основном является изображение с числовыми координатами, которые уже «решены», вы хотите поместить эти координаты в до того, как график будет рассчитан.В вашем случае:

ParametricPlot[
   {(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]} 
   /. {a -> 2, b -> 1, h -> 1},
   {t, 0, 2 \[Pi]}, 

 PlotRange -> All
]

alt text

3 голосов
/ 23 декабря 2010

Лучший способ использования локальных переменных в Mathematica - это Module[]:

Module[{a = 2, b = 1, h = 1}, 
   ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]}, 
   {t, 0, 2 \[Pi]}, 
   PlotRange -> All]]

Таким образом, a, b и h не получают назначенные значения в глобальном контексте, а только внутри Module. Если вы все еще хотите использовать правила замены, вам просто нужно ReleaseHold после того, как вы сделали замену:

ReleaseHold[
   Hold@ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]}, 
   {t, 0, 2 \[Pi]}, 
   PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}]

РЕДАКТИРОВАТЬ: Относительно того, почему это происходит. Насколько я понимаю, HoldAll предотвращает изменение аргументов функции с помощью любых правил (внутренних или явных). Что делает Hold, так это удерживает всю функцию (не только аргументы), и правило замены применяется после функция прошла оценку (чего не было, так что до сих пор нет) что-то там заменить) и HoldAll больше не действителен.

In[1]  := Hold[a /. a -> 5]
Out[1] := Hold[a /. a -> 5]
In[2]  := Hold[a] /. a -> 5
Out[2] := Hold[5]

Конечно, Hold также имеет HoldAll в качестве атрибута, так что это не объясняет, почему ParametricPlot HoldAll отличается. : - (

EDIT2: Я использовал Trace, чтобы посмотреть, что происходит, и кажется, что ReplaceAll применяется только в самом конце, когда ParametricPlot уже превратился в графический объект (и больше не содержит a, b или h). В случае Hold[a] /. a -> 5 удержание оценивается как Hold[a], и тогда правило замены может быть успешно применено.

1 голос
/ 24 декабря 2010

Это не ответ как таковой, просто комментарий об использовании модуля с графиком.

Если я буду действовать следующим образом

f[t_] := {(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - 
   h Sin[(a + b)/b t]}

Следующее НЕ будет работать

Метод 1:

Module[{a = 2, b = 1, h = 1}, 
 ParametricPlot[f[t], {t, 0, 2 \[Pi]}, PlotRange -> All]]

Метод 2:

Module[{a = 2, b = 1, h = 1}, 
 ParametricPlot[Evaluate[f[t]], {t, 0, 2 \[Pi]}, PlotRange -> All]]

Работает следующее (Метод 3)

ParametricPlot[
 Module[{a = 2, b = 1, h = 1}, Evaluate[f[t]]], {t, 0, 2 \[Pi]}, 
 PlotRange -> All]

, как и метод, описанный выше (метод4)

Module[{a = 2, b = 1, h = 1}, 
   ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]}, 
   {t, 0, 2 \[Pi]}, 
   PlotRange -> All]]

Кто-нибудь может объяснить, почему метод 4 работает, а метод 2 - нет?(То же самое относится и к «С», который я нахожу более интуитивно понятным для модуля).

Для чего бы это ни стоило, я бы сгенерировал оригинальный параметрический график, используя правила замены следующим образом:

ParametricPlot[
 Evaluate[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - 
     h Sin[(a + b)/b t]}] /. {a -> 2, b -> 1, h -> 1}, {t, 0, 
  2 \[Pi]}, PlotRange -> All]

РЕДАКТИРОВАТЬ

f[x_] := (a x)/(b + x);
With[{a = 10, b = 100}, Plot[Evaluate[f[x]], {x, 0, 100}]]
With[{a = 10, b = 100}, Plot[(a x)/(b + x), {x, 0, 100}]]
Plot[With[{a = 10, b = 100}, Evaluate[f[x]]], {x, 0, 100}]
Plot[Evaluate[f[x]] /. {a -> 10, b -> 100}, {x, 0, 100}]

Метод 1 (из Edit) не работает (потому что 'Plot' обрабатывает переменную x как локальную, эффективно используя Block '?)

Мне кажется, что это абсолютноПонятно всем, даже тем, кто имеет элементарные знания Mathematica, что происходит с методом 2, демонстрируя мощь и простоту использования Mathematica.Когда уравнения становятся более сложными, выгодно ли определять их отдельно.Сейчас не так ясно, что метод 3 должен использоваться вместо метода 1. (Метод 4, конечно, вероятно, лучший из всех.)

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