Математика. Настоящий учебник посвящен системе Mathematica прикладному пакету компьютерной алгебры, при помощи которого можно решать любые задачи, в которых в той или иной форме встречается математика
Скачать 4.43 Mb.
|
{x+y+z==1,x*y*z==1},y]] Out[56]=x*z*(-1+x+z)==-1 In[57]:=Simplify[Eliminate[ {x+y+z==1,x^2+y^2+z^2==1},y]] Out[57]=x^2+x*z+z^2==x+z Если нам нужно одновременно исключить несколько неизвестных, то эти неизвестные тоже должны задаваться в виде списка. Вот пример, где мы ищем соотношение между суммами степеней, для чего требуется исключить сразу две неизвестных: In[58]:=Simplify[Eliminate[ {u==x^5+y^5,v==x^3+y^3,w==x^2+y^2}, {x,y}]] Out[58]=2*u^3+30*u*v^2*w^2+5*v*w^6== v^5+15*u^2*v*w+15*v^3*w^3+6*u*w^5 Ясно, что уже в подобном примере выполнение исключения вручную тре- бует известного присутствия духа и уверенности в своих технических воз- можностях. 74 При применении команды Eliminate система пытается известными ей методами исключать и неизвестные из трансцендентных уравнений, конеч- но, не всегда одинаково успешно. • Решение неравенств. Естественно, Mathematica может решать не только уравнения, но и неравенства. В § 1 мы уже видели, что неравенство записывается обычным образом: ◦ Строгое неравенство x>y Greater или x Обычно система считает, что связанные неравенством величины представ- ляют собой вещественные числа, но она производит и некоторые упроще- ния частей неравенства и в том случае, когда они не являются числами, хотя и не может в этом случае приписать неравенству значение истинности True или False. Основной командой для решения неравенств и систем неравенств в языке Mathematica является Reduce. В простейшем варианте команда Reduce вызывается в формате Reduce[expression, {x,y}] где x, y это переменные, относительно которых мы хотим разрешить систе- му уравнений, неравенств и логических высказываний, а expression пред- ставляет собой произвольную логическую комбинацию следующих вещей: ◦ уравнений f[x,y,...]==f[x,y,...], ◦ неравенств f[x,y,...]!=f[x,y,...], ◦ строгих неравенств f[x,y,...] ◦ спецификаций доменов Element[x,domain], утверждающих, что x при- надлежит домену domain. ◦ кванторов всеобщности ForAll[x,condition[x],test[x]], возвраща- ющих значение True, если тест test[x] принимает значение True для всех значений x, для которых выполняется условие condition[x]. ◦ кванторов существования Exists[x,condition[x],test[x]], возвра- щающих значение True, если существует значение x, удовлетворяющее условию condition[x], для которого тест test[x] принимает значение True. По умолчанию команда Reduce считает, что все входящие в нее неизвест- ные принимают комплексные значения, причем все неизвестные, которые явным образом входят в строгие и нестрогие неравенства — веществен- ные. Поэтому для решения неравенств в вещественных числах никаких спецификаций доменов задавать не нужно. Если мы хотим решить систему неравенств в целых числах, то проще всего тоже не задавать специфици- кацию доменов для каждой переменной по отдельности, а сразу вызывать команду Reduce в формате: Reduce[expression, {x,y},Integers] 75 В случае одного неравенства использование команды Reduce и вид по- лучающегося при этом ответа ничем не отличается от того, что мы уже видели для команды Roots в случае одного уравнения: In[59]:=Reduce[x+(x-1)/(x+1)>0,x] Out[59]=-1-Sqrt[2] Разумеется, в общем случае, сводящемся к решению уравнений степени ≥ 3 решение будет выражено в терминах объектов типа Root: In[60]:=Reduce[x^2+(x-1)/(x^2+x+1)>1,x] Out[60]=x Для неравенств, сводящихся к уравнениям степени ≥ 4, мы всегда можем, при желании выразить ответ в радикалах, установив в теле функции оп- цию Cubics->True и/или Quartics->True, в следующем формате: In[61]:=Reduce[x^2+(x-1)/(x^2+x+1)>1,x,Cubics->True] Out[61]=x<1/3*(-2-2/(-17+3*Sqrt[33])^(1/3)+ (-17+3*Sqrt[33])^(1/3)||x>1 Разумеется, неравенство совсем не обязано с самого начала иметь поли- номиальный вид. С тем же успехом система решает любые неравенства, сводящиеся к алгебраическим, скажем, неравенства, содержащие абсолют- ные величины, квадратные корни и пр. Вот пример, основанный на задаче, фактически предлагавшейся на вступительном экзамене на экономический факультет МГУ: In[62]:=Simplify[Reduce[Abs[y]+x-Sqrt[x^2+y^2-1]>=1, {x,y}]] Out[62]=Element[y,Reals]&& (x==0&&(y==-1||y==1)|| 0 x>1&&(y<=-1||y>=1)) Обратите внимание, что так как y входит в неравенство не в явном виде, а в аргументе функций Abs и Sqrt, в ответе система считает нужным подчерк- нуть, что она считает y вещественным числом. При решении неравенств с абсолютными величинами нужно быть чрезвычайно аккуратным. Дело в том, что если все переменные входят в неравенства только под знаком аб- солютной величины, то система будет считать их комплексными. Поэтому, скажем, Reduce[Abs[x]+Abs[y]<1, {x,y}] вернет гораздо больше решений, чем Вы ожидали! Если вы хотите увидеть только вещественные решения, нужно явно специфицировать домен, вызывая эту команду в следующем формате: In[63]:=Reduce[Abs[x]+Abs[y]<1, {x,y},Reals] Out[63]=-1 76 решить соответствующее уравнение! Более того, даже для трансцендент- ных уравнений заведомо предпочтительно использовать именно команду Reduce, так как она всегда пытается определить все множество решений, а не просто какие-то решения. Однако во многих случаях при попытке най- ти точные решения неравенства ответом будет сакраментальное Reduce: This system cannot be solved with the methods available to Reduce. Модификации, которые необходимо внести в использование команды Re- duce для решение систем неравенств относительно нескольких неизвест- ных, точно такие же, как при использовании команды Solve для решения системы уравнений. А именно, в качестве первого аргумента команды Re- duce в этом случае можно задавать список неравенств, а в качестве второго — список неизвестных, приблизительно в таком формате: Reduce[ {f1[x,y]>g1[x,y],f2[x,y]>g2[x,y],...},{x,y}] С другой стороны, эту функцию можно вызывать и в следующем формате: Reduce[f1[x,y]>g1[x,y]&&f2[x,y]>g2[x,y]&&... },{x,y}] Однако следует иметь в виду, что уже решение простейших систем нера- венств может состоять из нескольких компонент — иногда из огромного числа компонент: In[64]:=Reduce[Abs[x]+Abs[y]>1&&x^2+x*y+y^2<1, {x,y}] Out[64]=-2/Sqrt[3] § 6. 77 § 5. Элементарные функции Я стал немного забывать теорию функций. Ну, это восстановится. Врач обещал ... врет, наверно. Владимир Высоцкий. `Дельфины и психи (записки сумасшедше- го)' Система Mathematica знает определения большого количества элемен- тарных и специальных функций, и громадное количество фактов об их значениях, их поведении, дифференциальные и функциональные уравне- ния, которым они удовлетворяют, etc., etc., etc. Эти знания в сочетании с мощью ее интеллекта позволяют без труда решать любую задачу об этих функциях, которая может встретиться школьнику, студенту и вообще лю- бому нематематику. • Экспоненты и логарифмы. Как мы уже упоминали, именами всех обычных функций в языке Mathematica являются либо их полные англий- ские названия, либо стандартные сокращения этих названий. Неспециа- лист должен иметь в виду, что — особенно в области элементарной матема- тики — многие английские сокращения, в частности, имена большинства тригонометрических и гиперболических функций, отличаются от конти- нентальных. В то же время русская педагогическая традиция основана на латинских и французских сокращениях! В соответствии с этим этим общим принципом экспонента и логарифм называются Exp и Log: ◦ Exp[x] возвращает e x ; ◦ Log[x] возвращает натуральный логарифм x; ◦ Log[b,x] возвращает логарифм x по основанию b. Обратите внима- ние на весьма необычный (для языка Mathematica!) порядок аргумента и параметра: в записи большинства функций аргументы предшествуют па- раметрам. Стоит предупредить, что в языке Mathematica есть и функция Expo- nent, но по-английски слово exponent означает как собственно экспоненту, т.е. степень, так и показатель степени. Так вот Exponent[f,x] обозначает наибольший показатель степени, с которым x входит в f . Экспонента и логарифм наряду с круговыми (“тригонометрическими”) и гиперболическими функциями являются примерами числовых функций. В Модуле 2 мы достаточно подробно обсуждаем специфику числовых функций, поэтому ограничимся пока констатацией того, что в тех слу- чаях, когда их аргументы принимают численные значения, эти функции всегда, когда это возможно, пытаются вернуть точные численные значе- ния. В природных условиях Mathematica работает с экспонентой и логариф- мом как комплексными функциями, считая при этом, что для логарифма разрез произведен по лучу (0, −∞). Вот, например, как Mathematica пони- мает формулу Эйлера: 78 In[65]:=ComplexExpand[Exp[x+I*y]] Out[65]=E^x*Cos[y]+I*E^x*Sin[y] А вот что такое логарифм отрицательного числа: In[66]:=Refine[Log[x],x<0] Out[66]=I*Pi+Log[-x] Использованная здесь команда Refine является одной из самых полезных команд системы при работе с числовыми функциями. Вызванная в фор- мате Refine[expression,assumptions] она упрощает выражение expression так как она сделала бы это при усло- вии, что входящие в него символы заменены явными числовыми значени- ями, удовлетворяющими предположениям assumptions. В действительно- сти во многих ситуациях, например, когда мы пытаемся упростить несколь- ко различных функций при одних и тех же предположениях, удобно вы- зывать Refine внутри вспомогательной команды Assuming, в следующем формате: Assuming[assumptions,Refine[expression]] Стоит подчеркнуть, что команда Refine не конкурирует с командами Simplify и FullSimplify, а дополняет их. Дело в том, что Simplify опи- рается главным образом на общие полиномиальные алгоритмы, в то время как Refine использует несколько сотен конкретных типов преобразований известных системе числовых функций. Например, не только Simplify, но даже FullSimplify не выполняет произведенного выше упрощения: In[67]:=FullSimplify[Log[x],x<0] Out[67]=Log[x] Это значит, что для упрощения формул, в которые входят значения чис- ловых функций, полезно применить к ним как команду Simplify, так и команду Refine. Используемые командой Refine предположения могут состоять из про- извольных логических комбинаций неравенств, уравнений и спецификаций доменов. Непосредственно в языке ядра описаны всего семь доменов: ◦ C = Complexes — комплексные числа, ◦ R = Reals — вещественные числа, ◦ Q = Algebraics — алгебраические числа (в документации фирмы Wol- fram Research этот домен обозначается через A, но большинство алгебра- истов использует обозначение A не для поля алгебраических чисел, а для кольца целых алгебраических чисел), ◦ Q = Rationals — рациональные числа, ◦ Z = Integers — целые числа, ◦ P = Primes — простые числа, ◦ {True,False} = Booleans — значения истинности. 79 При этом условие принадлежности элемента x домену Domain записывается в виде Element[x,Domain] Вот пример упрощения, использующего условие y ∈ Z: In[68]:=Refine[Exp[x+I*Pi*y],Element[y,Integers]] Out[68]=(-1)^y*E^x • Круговые и гиперболические функции. Естественно, в Mathema- tica имплементированы и все остальные основные элементарные функции, в частности, круговые, гиперболические, обратные круговые и обратные гиперболические. Все они рассматриваются как числовые функции (ком- плексного аргумента) и к ним относится все, что было сказано выше об экспоненте и логарифме. Работая с комплексными числами мы уже имели возможность убедиться, что косинус и синус называются Cos и Sin. Аргумент круговых функций выражается в радианах, причем по умолчанию всегда возвращается точное значение функции. Впрочем, как и для любой числовой функции, точное значение всегда можно превратить в приближенное, применяя функцию N: In[69]:= {Sin[Pi/12],Sin[Pi/8],Sin[1],N[Sin[1]]} Out[69]= {(-1+Sqrt[3])/(2*Sqrt[2]),Sin[Pi/8],Sin[1],0.841471} Однако при желании аргумент круговых функций можно выражать и в градусах, для этого его величину в градусах нужно умножить на константу Degree, равную численному значению π/180. Приведем первые 50 разрядов этой константы: In[70]:=N[Degree,50] Out[70]=0.017453292519943295769236907684886127134428718885417 Подчеркнем, что в отличие от Pi константа Degree имеет формат прибли- женного вещественного числа (хотя и неопределенной разрядности). Это значит, что Mathematica не может ответить на вопрос Pi/180==Degree. В то же время тест N[Pi/180,d]==Degree даст значение True при любом ко- личестве разрядов d. Тем не менее, к нашему большому удивлению, вычис- ление значений круговых функций от углов, выраженных в градусах, дает точные значения: In[71]:= {Cos[15*Degree],Sin[15*Degree]} Out[71]= {(1+Sqrt[3])/(2*Sqrt[2]),(-1+Sqrt[3])/(2*Sqrt[2])} Команда Refine работает обычным образом: In[72]:= {Refine[Cos[x+Pi/2]],Refine[Sin[Pi/2-x]]} Out[72]= {-Sin[x],Cos[x]} В соответствии с английской традицией тангенс и котангенс называются Tan и Cot: In[73]:= {Sin[x]/Cos[x],Cos[x]/Sin[x]} Out[73]= {Tan[x],Cot[x]} 80 Названия основных гиперболических функций получаются из названий соответствующих круговых функций дописыванием буковки h. Таким об- разом, например, гиперболический косинус и гиперболический синус на- зываются Cosh и Sinh, соответственно. Названия обратных функций по- лучаются из исходных функций приписыванием приставки Arc, при этом имя исходной функции не меняется (в частности, продолжает писаться с большой буквы). Таким образом, например, арккосинус и арксинус назы- ваются ArcCos и ArcSin, а гиперболический арккосинус и гиперболический арксинус — ArcCosh и ArcSinh, соответственно. • Значения элементарных функций. Одной из самых мощных и полезных команд системы Mathematica для работы со значениями число- вых функций является команда FunctionExpand, которая пытается приве- сти выражение к пусть и более длинному, но более “элементарному” виду. Таким образом, действие FunctionExpand в определенном смысле противо- положно действию команды Simplify, которая пытается представить вы- ражения в самом коротком виде, хотя бы как значения высших трансцен- дентных функций. При этом последовательное применение команд Func- tionExpand и Simplify обычно не возвращает исходное выражение, а пре- образует его к какому-то совсем другому виду! Команда FunctionExpand пытается сделать следующее: ◦ избавиться от явного применения операций анализа (дифференциро- вание, интегрирование и т.д.); ◦ выразить значения специальных функций в терминах элементарных функций и констант; ◦ выразить значения элементарных функций в терминах известных кон- стант и арифметических операций; ◦ упростить вид аргументов. Мы уже видели, что Mathematica не преобразует sin(π/8) к какому-либо другому виду, так как не считает, что, скажем, выражение этого значения в радикалах проще, чем sin(π/8). Однако выражение этого значения в радикалах “элементарнее”: In[74]:=FunctionExpand[ {Cos[Pi/8],Sin[Pi/8]}] Out[74]= {Sqrt[2+Sqrt[2]]/2,Sqrt[2-Sqrt[2]]/2} Для всех более сложных случаев поверх FunctionExpand рекомендуется применять Simplify: In[75]:=Simplify[FunctionExpand[Cos[2*Pi/7]]] Out[75]=-1/6+1/6*(7/2*(1-3*I*Sqrt[3]))^ (1/3)+ (I*(7/2*(1-3*I*Sqrt[3]))^ (2/3))/(3*I+9*Sqrt[3]) Если ответ все еще представляется Вам сложным, то только потому, что Вы не видели, что FunctionExpand возвратило до применения Simplify!! Команда FunctionExpand может применяться и к значениям числовых функций в случае символьных аргументов, удовлетворяющих определен- 81 ным предположениям. В этом случае она вызывается в том же формате, что и команда Refine: FunctionExpand[expression,assumptions] Однако она действует совершенно иначе, чем Refine. Это очень хорошо видно на следующем примере: In[76]:=Refine[Log[x*y],x>0&&y>0] Out[76]=Log[x*y] In[77]:=FunctionExpand[Log[x*y],x>0&&y>0] Out[77]=Log[x]+Log[y] • Структурные манипуляции. В ядре системы описаны основные структурные манипуляции в кольцах Trig R и Trig C вещественных и ком- плексных тригонометрических многочленов. Вот некоторые простейшие из них: ◦ TrigExpand представляет тригонометрический многочлен как линей- ную комбинацию одночленов одночленов cos(x) m sin(x) n ; ◦ TrigFactor раскладывает тригонометрический многочлен на множи- тели; ◦ TrigReduce приводит тригонометрическое выражение к наиболее про- стому с точки зрения системы виду. Возьмем функцию Cos[2*x]*Cos[3*x] и посмотрим, что с ней делают эти преобразования: In[78]:=TrigExpand[Cos[2*x]*Cos[3*x]] Out[78]=Cos[x]/2+Cos[x]^5/2-5*Cos[x]^3*Sin[x]^2+5/2*Cos[x]*Sin[x]^4 In[79]:=TrigFactor[Cos[2*x]*Cos[3*x]] Out[79]=2*Cos[x]*(-1+2*Cos[2*x])*Sin[Pi/4-x]*Sin[Pi/4+x] In[80]:=TrigReduce[Cos[2*x]*Cos[3*x]] Out[80]=1/2*(Cos[x]+Cos[5*x]) При решении уравнений в элементарных функциях предварительная об- работка уравнений этими преобразованиями обычно гораздо эффективнее, чем непосредственное применение команды Solve. Скажем, непосредствен- ное вычисление In[81]:=Solve[(Sin[x]+Cos[x])/Sqrt[2]+Cos[2*x]/Sqrt[3]==1,x] (пример, фактически предлагавшийся на вступительном экзамене по ма- тематике на экономический факультет) дает ответ, но это такой ответ, ко- торый сам не посмотришь и другим не покажешь. Конечно, правильная стратегия состоит в проведении следующего вычисления: In[81]:=TrigFactor[(Sin[x]+Cos[x])/Sqrt[2]+Cos[2*x]/Sqrt[3]] Out[81]=((3*Sqrt[2]+2*Sqrt[6]*Sin[Pi/4-x])*Sin[Pi/4+x])/ (3*Sqrt[2]) после чего решения уравнения непосредственно очевидны. 82 • Тригонометрические преобразования. К сожалению, довольно часто приходится вручную контролировать, какие именно преобразования проводятся с тригонометрическими выражениями. К этому приходится прибегать для функций больших степеней, сложного вида аргументов, а также в тех случаях, когда Вы хотите увидеть ответ в каком-то опреде- ленном виде. Дело в том, что система всегда может породить какой-то ответ, но может случиться, что он будет выражен не в той форме, кото- рая Вам нужна. Допустим, мы хотим выразить tg(x + y + z) в терминах tg(x), tg(y) и tg(z). Непосредственное применение tg(x + y + z) команды FunctionExpand приведет к нескольким строчкам косинусов и синусов x, y и z, от которых начинает рябить в глазах. В этом месте полезно вспомнить команду Together, приводящую дроби к общему знаменателю: In[82]:=Together[TrigExpand[Tan[x+y+z]]] Out[82]=(Cos[y]*Cos[z]*Sin[x]+Cos[x]*Cos[z]*Sin[y]+ Cos[x]*Cos[y]*Sin[z]-Sin[x]*Sin[y]*Sin[z])/ (Cos[x]*Cos[y]*Cos[z]-Cos[z]*Sin[x]*Sin[y]- Cos[y]*Sin[x]*Sin[z]-Cos[x]*Sin[y]*Sin[z]) Но это все еще не то, на что мы надеялись. Не приводит к успеху ни приме- нение FunctionExpand, Refine или Simplify. В этом случае нам не остается ничего другого, кроме как явно задавать правила преобразования, ко- торые мы хотим применить. Мы подробно описывает йогу замен, правил и подстановок в Модуле 2. Пока ограничимся замечанием, что применение правила lhs->rhs к выражению expression оформляется в виде: expression /. lhs->rhs если мы хотим однократно применить это правило ко всем частям выраже- ния и в виде expression //. lhs->rhs если мы хотим, чтобы система применяла правило не только к исходно- му выражению, но и к получающимся выражениям quantum satis, пока выражение не перестает меняться. Первая из этих форм называется Re- placeAll, а вторая — ReplaceRepeated. При этом само правило преобразования lhs->rhs задается в формате f[x ,y ]->g[x,y] где f (x, y) — функция, которую мы хотим переписать в виде g(x, y). Обра- тите особое внимание на бланки в левой части!!! Эти бланки делают x и y немыми переменными и сообщают системе, что это правило должно приме- няться, если подставить сюда вместо x и y любые символы и/или численные значения. Пропуск бланков является грубейшей синтаксической ошибкой. В этом случае система будет знать, что f(x, y) следует заменить на g(x, y), но это ее знание не будет распространяться на f (a, b), f (z, w) и т.д. Проиллюстрируем задание правил преобразования на примере. Допу- стим, мы не знаем, что команда TrigFactor автоматически переписывает 83 ctg(x) − ctg(y) в виде − sin(x − y)/(sin(x) sin(y)) и хотим задать соответ- ствующее правило преобразования. В этом случае мы можем задать его в виде Cot[x ]-Cot[y ]->-Sin[x-y]/(Sin[x]*Sin[y]) Вернемся теперь к разложению tg(x + y + z) и заставим систему преобразо- вывать tg(x + y) в (tg(x) + tg(y))/(1 − tg(x) tg(y)) столько раз, сколько она видит выражение такого вида: In[83]:=Together[Tan[x+y+z] //. Tan[x +y ]->(Tan[x]+Tan[y])/(1-Tan[x]*Tan[y])] Out[83]=(-Tan[x]-Tan[y]-Tan[z]+Tan[x]*Tan[y]*Tan[z])/ (-1+Tan[x]*Tan[y]+Tan[x]*Tan[z]+Tan[y]*Tan[z]) После приобретения некоторого опыта правила преобразования становятся одним из основных инструментов программирования на языке Mathemati- ca, позволяющим полностью контролировать вид ответа. • Экспоненциальная и тригонометрическая форма. Функции x 7→ cos(ax) и x 7→ sin(ax) порождают то же пространство, что x 7→ e iax и x 7→ e −iax . Следующие команды осуществляют пересчет из тригонометри- ческого базиса в экспоненциальный и наоборот: ◦ TrigToExp — преобразование выражения из тригонометрической фор- мы в экспоненциальную; ◦ ExpToTrig — преобразование выражения из экспоненциальной формы в тригонометрическцю. В следующих вычислениях мы преобразуем тригонометрическое выра- жение в экспоненциальную форму: In[84]:=FactorTerms[TrigToExp[Cos[2*x]*Cos[3*x]]] Out[84]=1/4*(E^(-I*x)+E^(I*x)+E^(-5*I*x)+E^(5*I*x)) In[85]:= {TrigToExp[Tan[x]],TrigToExp[Cot[x]]} Out[85]= {(I*(E^(-I*x)-E^(I*x)))/(E^(-I*x)+E^(I*x)), -(I*(E^(-I*x)+E^(I*x)))/(E^(-I*x)-E^(I*x)) } Функция FactorTerms применена, чтобы вынести общий численный мно- житель. Вот еще один очень интересный пример. По умолчанию команды типа Solve записывают первообразные корни из 1 степени 5 в экспоненциальном виде: In[86]:=Solve[x^4+x^3+x^2+x+1==0,x] Out[86]= {{x->-(-1)^(1/5)},{x->(-1)^(2/5)}, {x->-(-1)^(3/5)},{x->-(-1)^(4/5)}} Однако большинство начинающих предпочтут увидеть их в тригонометри- ческом виде: In[87]:=Map[ExpToTrig,Solve[x^4+x^3+x^2+x+1==0,x],3] Out[87]= {{x->-1/4-Sqrt[5]/4-1/2*I*Sqrt[1/2*(5-Sqrt[5])]} 84 {{x->-1/4+Sqrt[5]/4+1/2*I*Sqrt[1/2*(5+Sqrt[5])]} {{x->-1/4+Sqrt[5]/4-1/2*I*Sqrt[1/2*(5+Sqrt[5])]} {{x->-1/4-Sqrt[5]/4+1/2*I*Sqrt[1/2*(5-Sqrt[5])]} Команда Map, вызванная в формате Map[f,list,d] применяет функцию f к списку list на уровне d. В приведенном выше примере ExpToTrig применяется на уровне 3. На уровне 3 в выражении, получающемся после применения Solve, лежат x и собственно корни из 1. Однако ясно, что с x команда ExpToTrig ничего не делает. • Экстремумы функции. При помощи системы Mathematica можно провести “исследование функций”. Упомянем лишь часто встречающуюся задачу отыскания максимумов и минимумов. Основными командами для этого являются Maximize и Minimize. Так как их использование абсолютно аналогично, в дальнейшем мы будем говорить только о Maximize. Для поиска глобального максимума можно вызывать эту команду в формате Maximize[f[x],x] При этом ответ возвращается в формате {a,{x->c}} с указанием макси- мума a функции x 7→ f(x) и какого-то (обычно наименьшего) значения аргумента c, в котором этот максимум достигается. Разумеется, глобальный максимум не обязан существовать или может быть бесконечным. Например, при попытке вычислить Maximize[x^2,x] мы получим сообщение Maximize: The maximum is not attained at any point satisfying the given constraints. и ответ {Infinity,{x->-Infinity}}. В действительности гораздо чаще приходится производить не глобаль- ную оптимизацию, а оптимизацию с ограничениями constraints. Для этого функции Maximize и Minimize вызываются в формате Maximize[ {f[x],constraints},x] где constraints обозначает ограничения или условия, при которых ищется экстремум. Вот, скажем, как ищется максимум функции f на отрезке [a, b]: Maximize[ {f[x],a<=x<=b},x] Однако уже для очень простых трансцендентных функций явная оптими- зация может приводить к довольно сложным ответам: In[88]:=FullSimplify[Maximize[ {Sqrt[x]-Exp[x],0<=x<=2},x]] Out[88]= {(-1+ProductLog[1/2])/Sqrt[2*ProductLog[1/2]], {x->1/2*ProductLog[1/2]}} Встречающаяся здесь функция ProductLog[x] представляет собой главное решение уравнения ye y = x, удовлетворяющее дифференциальному урав- нению dy dx = y x(1 + y) . Эта функция очень часто возникает при решении уравнений, в которые входят экспонента и/или логарифм. 85 В данном случае нам крупно повезло, что нашлась функция, решающая возникающее при оптимизации уравнение. Однако в большинстве случа- ев, сводящихся к решению трансцендентных уравнений, система будет не в состоянии найти точные максимумы и минимумы. Например, попытка вычислить In[89]:=Maximize[ {Log[x]+Sin[x],0<=x<=5},x] не даст никакого вразумительного ответа. В подобных случаях можно при- менять команды численной оптимизации NMaximize и NMinimize. Эти ко- манды вызываются точно в таком же формате, как команды Maximize и Minimize и дают приближенные значение экстремума и той точки, в кото- рой оно достигается: In[90]:=NMaximize[ {Log[x]+Sin[x],0<=x<=5},x] Out[90]= {1.60552,{x->2.07393}} § 6. Графики функций Die Mathematik ist vielmehr eine Wissenschaft f¨ ur das Auge als eine f¨ ur das Ohr. — Математика в гораздо большей степени обращается к глазу, чем к уху. Carl Friedrich Gauß Und was man sieht und abzeichnet ist in der Regel immer sch¨ oner als was man nur so selbst erfindet. — И то, что срисовываешь с натуры, всегда получается лучше того, что пытаешься высосать из пальца. Wilhelm Hauff Из-за искажения масштаба дисплеем компьютера окружность вы- глядит как эллипс. Владимир Дьяконов 30 A conjecture both deep and profound Is whether the circle is round; In a paper by Erd¨ os, written in Kurdish, A counterexample is found. 31 В действительности c точки зрения профессионала одной из самых силь- ных сторон системы Mathematica, являются огромные возможности визу- ализации вычислений. С практической точки зрения эти возможности ограничены только способностью пользователя призывать их. Дело в том, 30 В настоящей книге встречаются изредка неправильно истолкованные не цита- ты (misconstrued misquotations), но именно этот эпиграф самый что ни на есть подлин- ный!!! Тот, кто думает, что мы его снова разыгрываем, может сам взглянуть на рисунок и легенду к нему на странице 323 следующей книги: В.П.Дьяконов, Mathematica 4. — Питер, 2001, с.1–654. 31 Окружность я не рисовал, я с детства рисовал овал. — Поль Эрдеш (перевод с курдского). 86 что хотя картинки произвольно высокой сложности могут быть порожде- ны чрезвычайно простыми формулами, способность фактически устано- вить полное соответствие между вычислениями и графикой требует, как минимум, ◦ хорошего понимания математики, стоящей за этими формулами, ◦ свободного владения функциональным программированием, ◦ собственно навыка применения графических команд, настройки их оп- ций и т.д., которые приобретаются только в результате длительных упражнений. По- этому в настоящем параграфе мы опишем только применение небольшого числа встроенных команд для построения графиков функций одной и двух переменных — и то только в простейших вариантах. • Построение графиков. График функции строится при помощи ко- манды Plot, которая порождает объект формата Graphics. В простейшем варианте, когда Вы доверяете системе принять вместо Вас все эстетические решения, эта команда вызывается в формате: Plot[f[x], {x,a,b}] Эта команда порождает график функции f (x), когда x меняется от a до b. Однако в действительности, у команды Plot еще несколько десятков факультативных аргументов, называемых опциями. Все они вместе с их значениями по умолчанию могут быть получены командой In[91]:=Options[Plot] Мы не будем обсуждать использование большинства из этих опций. Но для того, чтобы увидеть то, что Вам хочется, и так, как Вам этого хочется, поучимся настраивать самые важные: хотя бы AspectRatio и PlotRange, может быть, еще PlotStyle, Axes, AxesStyle, Ticks, GridLines, PlotLabel и TextStyle. Действительно, без понимания того, как работают AspectRa- tio и PlotRange — как наглядно продемонстрировал В.П.Дьяконов — не удастся узнаваемо нарисовать ровным счетом ничего, даже окружность. Вот как выглядит типичный вызов функции Plot. На рисунке 1 мы видим график функции x 7→ ln(x) + sin(x), построенный при помощи сле- дующей команды: In[92]:=Plot[Log[x]+Sin[x], {x,0,5}, AspectRatio->Automatic, PlotRange-> {-3,2}, PlotStyle->AbsoluteThickness[1.5], AxesStyle->AbsoluteThickness[1], GridLines->Automatic, PlotLabel->"Рис. 1: Log[x]+Sin[x]"] 87 1 2 3 4 5 -3 -2 -1 1 2 Рис . 1: Log[x]+Sin[x] Разумеется, мы получили бы график той же функции и напечатав просто In[93]:=Plot[Log[x]+Sin[x], {x,0,5}] без всяких там опций. Но это был бы совсем не такой красивый и инфор- мативный график, поэтому поясним использование опций. ◦ AspectRatio задает форматное отношение, т.е. отношение высоты рисунка к его ширине. Например, AspectRatio->2 означает, что высота в два раза больше ширины, а AspectRatio->1/2 — что ширина в два раза больше высоты. Форматное отношение по умолчанию равно 1/GoldenRa- tio. Это означает, что рисунок имеет те же пропорции, что стандартный лист бумаги формата A4 в альбомной ориентации (landscape orienta- tion). В то же время, отношение равное GoldenRatio означало, бы, что рисунок имеет пропорции стандартного листа бумаги формата A4 в книж- ной ориентации (portrait orientation). Мы обычно полагаем ⋆ либо AspectRatio->1 — в этом случае рисунок вписывается в квадрат; ⋆ либо AspectRatio->ysize/xsize, где ysize равно разности концов от- резка PlotRange, а xsize=b-a — в этом случае масштаб по осям одинаков; ⋆ либо AspectRatio->Automatic — в этом случае система сама решает, что больше соответствует обстановке, и во всех обычных случаях пытается задать одинаковый масштаб по осям. Конечно, это не всегда получается. Например, если функция f очень быстро растет или убывает, то ее значения могут превосходить значения x в тысячи раз. 88 ◦ PlotRange задает диапазон графика, т.е. те значения y, которые на нем отображаются. Когда функция слишком быстро растет или убывает, система не всегда удачно выбирает значение PlotRange и отсекает наиболее интересные части графика. Поэтому часто приходится задавать диапазон вручную: ⋆ PlotRange->All пытается поместить на график все значения функции f при x меняющемся в заданных пределах; ⋆ PlotRange-> {c,d} предлагает команде строить только ту часть графи- ка, которая помещается в горизонтальную полосу c ≤ y ≤ d. Обратите внимание, что в предществующем примере мы сознательно выбрали PlotRange так, чтобы ysize равнялось xsize. При этом установка AspectRatio->Automatic приводит к тому, что масштаб по осям одинаков. ◦ PlotStyle задает стиль графика, т.е. значения применяемых к нему графических директив. Типичными графическими директивами явля- ются задаваемые в типографских точках директивы ширина = Thickness и абсолютная ширина = AbsoluteThickness, штриховка = Dashing и абсолютная штриховка = AbsoluteDashing, описывающие плотность и прерывистость кривой, а также такие директивы, как уровень серого = GrayLevel, меняющийся от 0 (черный) до 1 (белый) и многочисленные директивы управления цветом: тон = Hue, задаваемый списком трех коор- динат HSB (Hue, Saturation, Brightness) и цвет = RGBColor, задаваемый списком трех координат RGB (Red, Green, Blue), etc., etc. В данном случае посредством PlotStyle->AbsoluteThickness[1.5] мы задали ширину кривой, приблизительно отвечающую насыщенности жир- ного шрифта. По умолчанию ширина соответствует насыщенности обыч- ного шрифта. ◦ AxesStyle задает стиль осей, т.е. значения графических директив, применяемых к осям. В этот момент читатель должен догадаться, что на- печатав AxesStyle->AbsoluteThickness[1], мы добились того, чтобы оси имели ширину в 1 пункт, чуть меньшую, чем насыщенность полужирного шрифта. ◦ GridLines задает координатную сетку, т.е. прямые, параллельные координатным осям. По умолчанию GridLines->None, так что никаких прямых, кроме самих осей не проводится. ⋆ GridLines->Automatic — прямые проводятся через метки (Ticks) на осях; ⋆ GridLines-> {{x1,...,xm},{y1,...,yn}} — прямые, параллельные оси y, проводятся через точки x 1 , . . . , x m на оси x, а прямые, параллельные оси x — через точки y 1 , . . . , y n на оси y. В данном случае мы задали опцию GridLines->Automatic, что побудило систему проводить прямые через целые точки на осях. ◦ PlotLabel задает ярлык графика, т.е. заголовок или название, ко- торое обычно пишется над графиком. Если Вам хочется перевести Label 89 как метка, не торопитесь, так как метка или засечка является стандарт- ным переводом термина Tick, который встретится нам далее. Другими близкими опциями являются ⋆ ярлыки осей = AxesLabel — текст, который пишется на осях, ⋆ ярлыки рамки = FrameLabel — текст, который пишется на рамке, ⋆ легенда = PlotLegend — помещенные в рамочку пояснения под гра- фиком. Обратите внимание, что включенный в задание опции PlotLabel текст "Рис. 1: Log[x]+Sin[x]" заключается в кавычки. Это превращает этот текст из последовательности символов в стринг = String, текстовый объ- ект, воспринимаемый и воспроизводимый verbatim (буква в букву). Над стрингом не производятся никакие обычные вычисления. Иными словами, все специальные символы, которые в иных условиях интрепретировались бы как операторы, в составе стринга представляют собой просто типограф- ские знаки. Следует иметь ввиду, что имеются специальные текстовые команды, при помощи которых проводятся преобразования стрингов. Комментарий. Отметим, что те картинки, которые Вы видите в этой книге, порожде- ны при помощи несколько более сложного выбора опций. Дело в том, что при подготовке оригинал-макета книги нам еще нужно было привести в соответствие встречающийся в ярлыках, метках и легендах шрифт в соответствие со шрифтом, использованным в ос- новном тексте. Текст этой книги набран с использованием гарнируры Times New Roman, в то время как стандартные настройки Mathematica порождают вывод шрифтом Couri- er. Это значит, что в действительности для задания ярлыков нам приходилось печатать что-то в таком духе: PlotLabel->StyleForm["Рис. 1: Log[x]+Sin[x]", FontFamily->"Times", FontWeight->"Bold", FontSize->12] С целью изменения шрифта меток пришлось включать в тело команды опцию TextStyle-> {FontFamily->"Times",FontSize->12} Обратите внимание на задание опции внутри опции!!! Понятно, что все эти вещи дела- лись исключительно из типографских соображений и при проведении реальных вычис- лений никому не следует подобными вещами злоупотреблять. • Основная формула тригонометрии. Во многих школьных учеб- никах упоминается “основная формула тригонометрии”, которая записы- вается в форме cos 2 (x) + sin 2 (x) = 1. Однако каждый может моментально проверить, что в таком виде эта формула безнадежно неверна. В этом легко убедиться, например, заметив, что cos 2 (π/2) + sin 2 (π/2) = 1 + sin(1) 6= 1. Для того, чтобы развеять все вредные иллюзии, изобразим на рисунке 2 график функции x 7→ cos 2 (x) + sin 2 (x), построенный при помощи следую- щей команды: In[94]:=Plot[Sin[Sin[x]]+Cos[Cos[x]], {x,-3*Pi,3*Pi}, PlotRange-> {0,2}, AspectRatio->1/5, 90 Ticks-> {Table[n*Pi,{n,-3,3}],{1,2}}, AxesStyle->AbsoluteThickness[1], PlotStyle->AbsoluteThickness[1.5], PlotLabel->"Рис. 2: Sin[Sin[x]]+Cos[Cos[x]]"] -3 π -2 π -π 0 π 2 π 3 π 1 2 Рис . 2: Sin [Sin[x]]+Cos[Cos[x]] Повторимся, что мы могли получить почти такой же результат и напечатав просто In[95]:=Plot[Sin[Sin[x]]+Cos[Cos[x]], {x,-3*Pi,3*Pi}] без всяких опций. Все остальное — это декорации и отделка деталей. Большая часть этого текста должна быть Вам уже знакома после разбо- ра предыдущего примера. Обратите внимание на то, что порядок задания опций не имеет значения. В предыдущем примере мы вначале определи- ли AspectRatio, а потом PlotRange, но никто не мешает нам задавать их в другой последовательности. Кроме того, в этом примере встречается новая опция ◦ Ticks — это метки или засечки, т.е. характерные точки, отмечаемые на осях. По умолчанию Ticks->Automatic и система сама отмечает такие точки. Однако возможны другие установки: ⋆ Ticks->None — метки на осях не ставятся; ⋆ Ticks-> {{x1,...,xm},{y1,...,yn}} — метки на оси x ставятся в точ- ках x 1 , . . . , x m , а на оси y — в точках y 1 , . . . , y n В данном случае нам показалось, что для этого графика на оси x гораздо естественнее отмечать целые кратные π, а вовсе не целые числа. При этом, чтобы чуть сократить ввод с клавиатуры и облегчить возможность даль- нейших изменений, мы породили множество целых кратных π как список посредством команды Table, см. § 10 настоящей главы. То соотношение между основными тригонометрическими функциями, которое действительно имеет место, это не какая-то мифическая “основ- ная формула тригонометрии”, а теорема Пифагора cos(x) 2 + sin(x) 2 = 1. Мы надеемся, что после подобной наглядной демонстрации того, к каким грубым ошибкам неизбежно приводят неряшливые обозначения, читатель будет тщательно различать возведение в квадрат функции и возведение в квадрат ее значения! Если к этому моменту Вам надоело печатать при построении каждого графика AspectRatio->1 или AspectRatio->Automatic, то Вы абсолютно правы. В действительности, если Вы на протяжении сессии собираетесь 91 строить графики нескольких функций, имеет смысл с самого начала изме- нить опции команды Plot и/или других используемых Вами графических команд. Например, для того, чтобы во всех графиках, которые Вы строите на протяжении сессии, форматное отношение стало по умолчанию равным 1, а метки на осях не ставились, нужно лишь один раз в начале сессии произвести следующее вычисление: In[96]:=SetOptions[Plot,AspectRatio->1,Ticks->None] Смысл этого вычисления состоит в том, что при этом опциям AspectRatio и Ticks присваиваются новые значения, отличные от задаваемых по умол- чанию, и эти новые значения действуют на протяжении всей сессии, пока не будут снова изменены или переопределены. • Несколько функций на одном графике. Особенно интересна воз- можность строить графики нескольких функций на одной картинке. Вы- званая в формате Plot[ {f1[x],f2[x],...},{x,a,b}] команда Plot одновременно строит графики функций f 1 (x), f 2 (x), . . . при x меняющемся от a до b. Например, очень интересно сравнить графики функций sin, sin 2 и x 7→ sin(x) 2 . Это можно сделать при помощи следующей команды: In[97]:=Plot[ {Sin[x],Sin[Sin[x]],Sin[x]^2},{x,-2*Pi,2*Pi}, PlotStyle-> {{AbsoluteThickness[1.5], Dashing[{0.002,0.02}]}, {AbsoluteThickness[1], GrayLevel[0]}, {AbsoluteThickness[1], Dashing[{0.03}]}}, AxesStyle->AbsoluteThickness[1], PlotLabel->"Рис. 3: Sin[x], Sin[Sin[x]], Sin[x]^2", Ticks-> {{-2*Pi,-3*Pi/2,-Pi/2,0,Pi/2,3*Pi/2}, {-1,0.5,1}}] -2 π - 3 π 2 - π 2 π 2 3 π 2 -1 0.5 1 Рис . 3: Sin[x], Sin[Sin[x]], Sin[x]^2 92 Результат этого вычисления воспроизведен на Рисунке 3. Отметим лишь те моменты, которые нам раньше не встречались. ◦ Значения графических директив для списка функций тоже могут зада- ваться списком, при этом первый элемент этого списка будет применяться к первой функции, второй — ко второй и т.д. Например, в данном случае мы рисуем график первой функции с толщиной линии 1.5, а график второй и третьей — с толщиной 1. Это делается для того, чтобы они производили впечатление одинаковой жирности. ◦ Директива Dashing описывает штриховку. При этом ее аргумент за- дается в виде списка, элементы которого определяют длины последова- тельных сегментов кривой, из которых нечетные закрашиваются, а чет- ные — не закрашиваются. После исчерпания элементов списка длины начинают циклически повторяться. При этом, в отличие от абсолютной штриховки = AbsoluteDashing, эти длины указываются не в каких-то аб- солютных величинах, а в долях от общего размера графика. Таким об- разом, Dashing[ {0.002,0.02}] описывает кривую, составленную из точек, расстояния между которыми в десять раз больше размера самих точек, а Dashing[ {0.03}] — кривую, состоящую из закрашенных и незакрашенных сегментов одинаковой длины. ◦ Наконец, директива GrayLevel[0] предписывает рисовать вторую кри- вую, а именно, график функции sin 2 , сплошной черной линией. Упражнение. Нарисуйте картинку, воспроизведенную на Рисунке 4. -2 - 3 2 - 2 2 3 2 -1 0.5 1 . 4: Cos[x], Cos[Cos[x]], Cos[x]^2 Указание. Обратите внимание на ярлык и метки! Стоит подчеркнуть, что штриховка здесь использована исключительно из типографских соображений. В обычных условиях для вывода картинки на экран или цветной принтер мы бы варьировали бы не штриховку, а цвет кривых. Иными словами, мы задавали бы опцию PlotStyle следующим образом: 93 PlotStyle-> {RGBColor[1,0,0],RGBColor[0,1,0],RGBColor[0,0,1]} При этом первая кривая изображается чистым красным цветом (в самом деле, RGBColor[1,0,0] означает максимальную насыщенность красного и нулевую насыщенность зеленого и синего), вторая — зеленым и третья — синим. Конечно, проще печатать, используя системные названия цветов PlotStyle-> {Red,Green,Blue} Еще одна интересная представляющаяся здесь возможность состоит в том, чтобы строить на одном графике вещественную и мнимую часть ком- плексной функции вещественной переменной. Например, на Рисунке 5 изображены графики вещественной и мнимой части дзета-функции Римана на критической прямой, причем вещественная часть изображена пункти- ром, а график мнимой части — сплошной. -60 -40 -20 20 40 60 -2 -1 1 2 3 4 . 5: Riemann Zeta Этот рисунок порожден при помощи следующего текста: In[98]:=Plot[ {Re[Zeta[1/2+x*I]],Im[Zeta[1/2+x*I]]},{x,-60,60}, PlotStyle -> {{AbsoluteThickness[1.5],AbsoluteDashing[{1,3}]}, {AbsoluteThickness[1],GrayLevel[0]}}, AxesStyle->AbsoluteThickness[1], PlotLabel->"Рис. 5: Riemann Zeta" Ticks -> Automatic] Все в этом тексте уже нам встречалось, за исключением ровно одного мо- мента: ◦ Для задания штриховки мы пользуемся не директивой Dashing, а ди- рективой абсолютная штриховка = AbsoluteDashing, аргумент которой представляет собой список длин последовательных сегментов кривой, за- даваемых в типографских пунктах. Таким образом, по замыслу график вещественной части состоит из точек размером 1 типографский пункт, раз- деленных промежутками в три типографских пункта. Однако из-за того, 94 что мы задали абсолютную толщину кривой в 1.5 пункта, точки выглядят больше, чем расстояния между ними. Можно, конечно, различить вещественную и мнимую части не штрихов- кой, а цветом, например, так: PlotStyle-> {RGBColor[1,0,0],RGBColor[0,0,1]} В этом случае на экране компьютера график вещественной части будет красным, а график мнимой части — синим. Стоит предупредить читателя об одной существенной тонкости. Дело в том, что команда Plot необычным образом вычисляет свой первый ар- гумент. Если быть совсем точным, она его вообще никак не вычисляет: специальный параметр HoldAll предписывает вычислять первый аргумент только после присвоения конкретных числовых значений переменной x. Это может приводить к ощутимым затратам времени, в частности, если первый аргумент является списком функций, например, при построении на одном графике 10 первых многочленов Чебышева командой Plot[Table[ChebyshevT[n, x], {n,1,10}],{x,-1.01,1.01}]] В подобных случаях полезно использовать директиву Evaluate, которая от- меняет действие указанного параметра, что сокращает время, затрачива- емое на построение графика. С её использованием построение графика таблицы функций может быть осуществлено следующим образом: Plot[Evaluate[Table[f[i][x], {i,1,n}]],{x,xmin,xmax}] Вот, например, как выполнено построение графика 10 первых многочле- нов Чебышева, представленное на рисунке 6: In[98]:=Plot[Evaluate[Table[ChebyshevT[n,x], {n,1,10}]], {x,-1.01,1.01}, AspectRatio->Automatic, PlotStyle->AbsoluteThickness[0.8], PlotRange-> {-1.7,1.7}, Ticks-> {{-1,-0.5,0.5,1,1.5},{-1,-0.5,0.5,1}}, PlotLabel->StyleForm["Рис. 6: Chebyshev polynomials"]] 95 -1 -0.5 0.5 1 -1 -0.5 0.5 1 . 6: Chebyshev polynomials Все остальные моменты, кроме только что объясненной необходимости ис- пользования команды Evaluate, уже встречались нам в предыдущих при- мерах. • Параметрический график. Еще один важнейший способ постро- ить объект формата Graphics состоит в том, чтобы использовать команду ParametricPlot. В простейшем варианте эта команда вызывается в следу- ющем формате: ParametricPlot[ {f[t],g[t]},{t,a,b}] Эта команда порождает графический объект, изображающий кривую, опи- сываемую точкой с координатами (f (t), g(t)), когда t меняется от a до b. Например, во многих областях естествознания возникают фигуры Лис- сажу, т.е. траектории точки, совершающей гармонические колебания в двух ортогональных направлениях. Конкретный вид этой фигуры опре- деляется периодами, разностью фаз и амплитудами колебаний. Например, на Рисунке 7 изображена фигура Лиссажу, отвечающая отношению пери- одов 3/7 и разности фаз π/2: In[99]:=ParametricPlot[ {Cos[3*t],Sin[7*t]},{t,0,2*Pi}, PlotStyle->AbsoluteThickness[1.5], AxesStyle->AbsoluteThickness[1], AspectRatio->Automatic, PlotLabel->"Рис. 7: Lissajout[3/7,Pi/2]"] 96 -1.0 -0.5 0.5 1.0 -1.0 -0.5 0.5 1.0 . 7: Lissajout[3/7,Pi/2] Упражнение. Постройте кривые Лиссажу, изображенные на рисунках 8–10: -1.0 -0.5 0.5 1.0 -1.0 -0.5 0.5 1.0 . 8: Lissajout[3/7,Pi/4] -1.0 -0.5 0.5 1.0 -1.0 -0.5 0.5 1.0 . 9: Lissajout[5/7,Pi/4] 97 -1.0 -0.5 0.5 1.0 -1.0 -0.5 0.5 1.0 . 10: Lissajout[5/7,Pi/6] Как и в случае команды Plot, мы можем изобразить несколько парамет- рических кривых на одной картинке. Для этого команду ParametricPlot нужно вызывать в следующем формате: ParametricPlot[ {{f1[t],g1[t]},{f2[t],g2[t]},...},{t,tmin,tmax}] Команда ParametricPlot имеет те же особенности, что и Plot. В частно- сти, если Вы задаете ее первый аргумент неявным образом, который требу- ет предварительной обработки до того как можно вычислять его значения, то к этому аргументу необходимо применить команду Evaluate. • График неявной функции. Пожалуй еще более замечательной, чем возможность строить параметрические графики, является возможность по- строения графиков неявных функций. Это делается при помощи команды ContourPlot. Работа этой команды основана на способности системы ре- шать системы уравнений (ее имплементация самым существенным образом взывает к команде Solve и др.) и, как и многие другие графические функ- ции требует довольно значительного компьютерного ресурса. Формат вызова команды для построения графика функции, заданной неяв- но, следующий: ContourPlot[f[x,y]==g[x,y], {x,a,b},{y,c,d}] где f (x, y) = g(x, y) — уравнение, решения которого мы хотим изобразить на графике, x меняется от a до b, а y меняется от c до d. На рисунках 11–14 представлены эллиптические кривые. Для непо- священного читателя заметим, что они называются так вовсе не потому, что похожи на эллипс, а потому, что их изучение было первоначально мотиви- ровано теорией эллиптических интегралов и эллиптических функ- ций, которые, в свою очередь, действительно впервые появились в работе братьев Бернулли при вычислении длины дуги эллипса. В прошлое деся- тилетие эллиптические кривые стали чрезвычайно знамениты в широких 98 кругах образованной публики благодаря той роли, которую они сыграли в доказательстве последней теоремы Ферма Эндрю Уайлсом 32 Вот, например, как строилась первая из этих кривых: In[100]:=ContourPlot[y^2==x^3-x, {x,-1.2,1.6},{y,-1,2}, AspectRatio->Automatic, ContourStyle -> {GrayLevel[0], Thickness[0.005]]}, AxesStyle->AbsoluteThickness[1], PlotRange-> {-1.7,1.7}, Ticks-> {{-1,-0.5,0.5,1,1.5},{-1,-0.5,0.5,1}}, PlotLabel->"Рис. 11: y^2=x^3-x"] -1.0 -0.5 0.0 0.5 1.0 1.5 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 . 11: y^2 =x^3-x Упражнение. Постройте эллиптические кривые, изображенные на рисун- ках 12–14, обращая при этом внимание на детали! 32 A.Wiles, Modular elliptic curves and Fermat's last theorem. — Ann. Math., 1995, vol.141, p.443–551. 99 -1.0 -0.5 0.0 0.5 1.0 1.5 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 . 14: y^2 =x^3-x+1 -1.0 -0.5 0.0 0.5 -1.0 -0.5 0.0 0.5 1.0 . 13: y^2 =x^3+x^2 0.0 0.2 0.4 0.6 0.8 1.0 -1.0 -0.5 0.0 0.5 1.0 . 12: y^2 =x^3 100 • Графическое представление неравенств. Еще одной совершенно изумительной функцией системы, которая за секунды проделывает то, на выполнение чего обычному человеку нужно трудиться полдня, является команда RegionPlot. Формат вызова функции: RegionPlot[f1[x,y] В результате изображаются те точки прямоугольника {(x, y) ∈ R 2 | a ≤ x ≤ b, c ≤ y ≤ d}, которые удовлетворяют неравенствам f 1 (x, y) < g 1 (x, y), f 2 (x, y) < g 2 (x, y), . . . Вот, например, как строится рисунок 15, изображающий решения систе- мы неравенств, которая обсуждалась в конце § 4: In[101]:=RegionPlot[Abs[x]+Abs[y]>1&&x^2+x*y+y^2<1, {x,-2,2},{y,-2,2}, AspectRatio->Automatic, PlotStyle->AbsoluteThickness[0.5], AxesStyle->AbsoluteThickness[1], MaxRecursion -> 10, PlotLabel->"Рис. 15: Abs[x]+Abs[y]>1&&x^2+x*y+y^2<1"] -2 -1 0 1 2 -2 -1 0 1 2 . 15: Abs[x]+Abs[y]>1&&x^2+x*y+y^2<1 101 Вот еще один совершенно замечательный пример, демонстрирующий возможности команды RegionPlot, – таблица, состоящая из графиков ре- шения неравенств |x| p + |y| q ≤ 1. -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 -1.0-0.5 0.0 0.5 1.0 -1.0 -0.5 0.0 0.5 1.0 .16: Hoelder balls Поясним, что при p = q решения этого неравенства представляют собой шары по отношению к метрике Гельдера или, коротко, шары Гельдера = H¨ older balls. Частными случаями метрики Гельдера являются ◦ городская метрика (при p = 1), ◦ обычная эвклидова метрика (при p = 2), ◦ метрика Чебышева (при p = ∞). Хорошо видно, что в городской метрике шар является квадратом (как и следовало ожидать!), в эвклидовой метрике — кругом (как и следовало ожидать!), а потом по мере того как p растет, его форма снова приближа- ется к квадрату: 102 In[102]:=GraphicsGrid[Table[RegionPlot[Abs[x]^p+Abs[y]^q<=1, {x,-1,1},{y,-1,1}, PlotStyle->AbsoluteThickness[1.5], AxesStyle->AbsoluteThickness[1], Ticks->None, DisplayFunction->Identity], {p,1,5},{q,1,5}], PlotLabel->"Рис.16: Hoelder balls"] Здесь используются две не встречавшиеся нам до сих пор команды. ◦ Вызванная в формате GraphicsGrid[ {u,v,w,...}] команда GraphicsGrid собирает графические объекты u,v,w,... в один объект, состоящий из одинаковых прямоугольников, в которые вписаны объекты u,v,w,... Вызванная в формате GraphicsGrid[ {{u,v,...},{w,z,...},...}] она делает то же самое, но при этом располагает прямоугольники, содер- жащие объекты u,v,w,z,..., в виде двумерной таблицы. В данном случае мы по отдельности строим 25 шаров, а потом соединяем их в один графи- ческий объект 5 × 5. Мы могли бы, например, строить Рисунки 7–10 и 11–14 на одной стра- нице при помощи команды GraphicsGrid. Но фактически мы поступали иначе, пользуясь командами двумерной графики, вручную задавая разме- ры прямоугольников, в которые вписаны отдельные части картинки. ◦ Опция DisplayFunction->Identity встроена в тело RegionPlot для того, чтобы подавить вывод промежуточных результатов на экран. По умолчанию DisplayFunction->$DisplayFunction, при этом выводилась бы не только окончательная таблица из 25 шаров, но и каждый из них по отдельности, по мере вычисления соответствующего |