Математика. Настоящий учебник посвящен системе Mathematica прикладному пакету компьютерной алгебры, при помощи которого можно решать любые задачи, в которых в той или иной форме встречается математика
Скачать 4.43 Mb.
|
◦ x[[i,j]] — элемент x в позиции (i, j); ◦ x,[[{i,j},{k,l}]] — подматрица порядка 2 матрицы x, стоящая на пересечении строк с номерами i, j и столбцов с номерами k, l; ◦ x[[i]] — i-я строка матрицы x; ◦ x[[All,j]] — j-й столбец матрицы x; ◦ Tr[x,List] — главная диагональ матрицы x; Так, например, x[[1]] и x[[-1]] обозначают, соответственно, первую и последнюю строку матрицы x, а x[[All,1]] и x[[All,-1]] — ее первый и последний столбец. Еще раз обратите внимание на отсутствие здесь сим- метрии между строками и столбцами! Столбец матрицы является строкой транспонированной матрицы, поэтому j-й столбец матрицы x можно поро- дить также посредством Transpose[x][[j]]. Разумеется, также и главную диагональ матрицы можно определять ты- сячей других способов, например, напрашивающимся Table[x[[i,i]], {i,1,Length[x]}]. Однако встроенная команда Tr[x,List] не только изящнее, но и работа- ет быстрее, хотя разница во времени становится по настоящему заметной только для матриц порядка несколько десятков тысяч. • Просмотр матриц. Чтобы увидеть матрицу не как вложенный спи- сок, а в традиционной записи, надо применить к ней одну из команд Table- Form или MatrixForm. Скажем, следующая строка определяет одну из са- мых важных в самой математике и ее приложениях матриц — матрицу Вандермонда V (x 1 , . . . , x n ). Собственно говоря, вся теория определите- лей построена исключительно для анализа этого примера: In[189]:= vandermonde[x ,n ]:=Table[x[j]^i, {i,0,n-1},{j,1,n}] 136 Посмотрим теперь, как выглядит матрица vandermonde[y,5]. Это делается при помощи команды MatrixForm. Вычислив In[190]:= MatrixForm[vandermonde[y,5]] мы увидим примерно следующий результат: V (y 1 , y 2 , y 3 , y 4 , y 5 ) = 1 1 1 1 1 y 1 y 2 y 3 y 4 y 5 y 2 1 y 2 2 y 2 3 y 2 4 y 2 5 y 3 1 y 3 2 y 3 3 y 3 4 y 3 5 y 4 1 y 4 2 y 4 3 y 4 4 y 4 5 Разумеется, здесь мы воспроизводим не то, что будет фактически отобра- жено в записной книжке Mathematica, а уже облагороженный TEX'овский аутпут типографского качества, получающийся с помощью применения по- верх MatrixForm команды экспорта TeXForm. Мы сами обычно не печатаем форматные команды TableForm, Matrix- Form и т.д. заранее, а применяем их к уже имеющемуся выражению в пост- фиксной форме (задним числом). Это делается при помощи оператора //, примерно так 44 In[191]:= vandermonde[y,5] // MatrixForm В первом приближении различие между командами TableForm и Matrix- Form такое же, как между matrix и pmatrix в TEX'е. Иными словами, Table- Form[x] выводит элементы матрицы x в виде таблицы, а MatrixForm[x] — в традиционной математической записи с использованием круглых скобок. Комментарий. В действительности, кроме этого очевидного отличия, между команда- ми TableForm и MatrixForm имеется большое количество тонких различий в том, как они по умолчанию трактуют горизонтальное (слева, сверху, по центру, по десятичной точке, по фиксированному символу и т.д.) и вертикальное (по верху, по низу, по центру, по базо- вой линии, по оси) выравнивание строк и столбцов и индивидуальных элементов внутри строки или столбца. Однако для большинства пользователей, которые интересуются ре- зультатом вычисления, а не получением типографского продукта профессионального или полупрофессионального качества, подобные тонкости не имеют большого значения. • Матричные единицы. Самыми важными с точки зрения профес- сионального математика матрицами являются стандартные матричные единицы e ij , у которых в позиции (i, j) стоит 1 и 0 во всех остальных ме- стах. Матрицы e ij , 1 ≤ i, j ≤ n, образуют базис M(n, K) как векторного пространства над K. Более того, это мультипликативный базис, в том смысле, что произведение двух базисных элементов либо равно 0, либо сно- ва представляет собой базисный элемент: e ij e hk = δ jh e ik . Таким образом, e ij e hk = 0, если j 6= h, в то время как e ij e jk = e ik . Вот одно из возмож- ных определений этих матриц в языке Mathematica. Конечно, теперь мы должны явно указывать не только i, j, но и порядок n: 44 Тот же вид результата может быть получен при выборе варианта представления TraditionalForm подменю Convert To - щелчок правой кнопкой мыши в пределах ячейки. 137 In[192]:= e[n ,i ,j ]:=Table[If[h==i,1,0]*If[k==j,1,0], {h,1,n},{k,1,n}] Еще раз обратите внимание на несколько уже встречавшихся нам принци- пиальных моментов: ◦ использование Blank и := SetDelayed для определения функции; ◦ использование == Equal в уравнениях i==h и j==k; ◦ использование условного оператора If[condition,x,y], возвращаю- щего x, если condition==True и y, если condition==False. Комментарий. Как мы обсуждаем в дальнейшем, в общем случае намного разумнее вызывать оператор If с четырьмя аргументами, в формате If[condition,x,y,z], явным образом предписывая, что следует делать в случае, когда система не может решить, выполняется условие condition или нет. Однако здесь мы используем этот оператор в чисто иллюстративных целях и только в простейшей ситуации сравнения небольших целых чисел, когда у системы не должно быть никаких сомнений, равны они или нет. В действительности вместо If[i==h,1,0] мы могли бы воспользоваться встроенной функ- цией KroneckerDelta, но это чуть длиннее. Посмотрим теперь, как выглядят стандартные матричные единицы сте- пени 3. Применив к ним форматную команду MatrixForm In[193]:= Map[MatrixForm,Flatten[Table[e[3,i,j], {i,1,3},{j,1,3}],1]] мы увидим следующее: 1 0 0 0 0 0 0 0 0 , 0 1 0 0 0 0 0 0 0 , 0 0 1 0 0 0 0 0 0 , 0 0 0 1 0 0 0 0 0 , 0 0 0 0 1 0 0 0 0 , 0 0 0 0 0 1 0 0 0 , 0 0 0 0 0 0 1 0 0 , 0 0 0 0 0 0 0 1 0 , 0 0 0 0 0 0 0 0 1 . Стоит подчеркнуть здесь один момент, не встречавшийся до сих пор. Де- ло в том, что команда Table[e[3,i,j], {i,1,3},{j,1,3}] создает вовсе не список из девяти стандартных матричных единиц, а вложенный список list, состоящий из трех списков в каждом из которых три матричные единицы! Таким образом, применение команды MatrixForm непосредствен- но к элементам этого списку даст нам совершенно не то, что хотелось. Команда Flatten[list,1] служит как раз для того, чтобы убрать один лишний вложенный уровень в list, а именно, верхний, и создать список из девяти матричных единиц (каждая из которых, конечно, сама является матрицей, т.е. вложенным списком!!) Применение команды Flatten[list] не достигло бы этой цели, так как убрало бы все вложенные уровни, создав список из 81 нуля и единицы. 138 • Разреженные матрицы. Разумеется, уже для матриц степени 100– 1000 подобные определения становятся чрезвычайно грубыми и непрактич- ными. В языке Mathematica предусмотрен специальный инструмент для генерации матриц, почти все элементы которых равны между собой (ска- жем, равны 0 или 1). Это команда SparseArray, которая порождает объект специального формата разреженный массив, в котором хранятся не все элементы матрицы, а только ее размеры, общий элемент и список позиций и элементов в них, где они отличаются от общего элемента. Разумеется, подобный объект должен обрабатываться специальными алгоритмами, так что большая часть обычных команд для работы с матрицами будут рас- сматривать его как сырой объект. Это значит, что для проведения мат- ричных вычислений при помощи стандартных функций необходимо еще конвертировать его в обычный матричный формат посредством команды Normal. Вот как, скажем, выглядит определение стандартной матричной единицы с использованием команды Sparse Array: In[194]:= e[n ,h ,k ]:=Normal[SparseArray[ {{h,k}->1},{n,n}]] Разумеется, в подобных случаях SparseArray используется в чисто ил- люстративных целях или для сокращения записи программ. Ясно, что при фактическом проведении матричных вычислений с матрицами поряд- ка нескольких десятков или сотен тысяч, разреженные матрицы невозмож- но перевести в обычный матричный формат, так как просто для хранения нескольких матриц такого размера — не говоря уже про какие-то вычисле- ния с ними! — в плотном формате потребуется вся доступная на бытовом компьютере память. § 11. Линейная алгебра 1000 вещей, которые можно сделать с Вашей любимой матрицей. Из учебника линейной алгебры В этом параграфе мы опишем как проводить некоторые простейшие мат- ричные вычисления. Как правило, для наглядности мы будем приводить не фактический аутпут системы Mathematica, а традиционную форму матриц, которая получается, если применить к получающимся матрицам Matrix- Form, а потом экспортировать результат в TEX'овском формате посредством TeXForm. • Решение систем линейных уравнений. Решение систем линейных уравнений осуществляется при помощи функций LinearSolve и NullSpace. А именно, функция LinearSolve ищет частное решение неоднородной си- стемы линейных уравнений, а функция NullSpace — общее решение одно- родной системы. Функция Linear Solve вызывается в различных форматах, в зависимо- сти от того, нужно ли нам решить одну линейную систему ax = b с данной матрицей a или (как весьма часто бывает в приложениях!) несколько си- стем с одной и той же матрицей и различными правыми частями. В первом случае функция LinearSolve вызывается в формате 139 LinearSolve[a,b] в то время как во втором случае — в формате LinearSolve[a][b] Разница состоит в том, что во втором случае система записывает факто- ризацию матрицы a, которая используется для решения системы ax = b. Если матрица a не обратима, то при вызове команды LinearSolve в таком формате выдается сообщение: LinearSolve: The matrix bla-bla-bla is singular so a factorization will not be saved. Приведем пример использования функции LinearSolve. Следующие ко- манды определяют случайную матрицу порядка m × n с целыми коэффи- циентами между −100 и 100 и случайный вектор высоты n с целыми ком- понентами в том же интервале: In[195]:= rama[m ,n ]:=Table[Random[Integer, {-100,100}], {i,1,m},{j,1,n}] In[196]:= cora[n ]:=Table[Random[Integer, {-100,100}],{i,1,n}] А именно, вызванная в формате Random[Integer, {k,l}], команда Random генерирует случайное целое число x, k ≤ x ≤ l, естественно, каждый раз новое. Кстати, почему мы задаем cora[n] отдельно? Почему мы не можем просто положить cora[n ]:=rama[1,n] или cora[n ]:=rama[n,1]? Тот, кто внимательно прочел предыдущий параграф, знает, почему! В самом деле, rama[m,n] — в том числе, конечно, rama[1,n] и rama[n,1] — представляют собой вложенные списки. Для того, чтобы получить cora[n] в правильном формате, мы должны были бы убрать один уровень вложенности, напри- мер, применив к этим спискам команду Flatten. Следующая команда фактически генерирует случайную 4 × 4-матрицу и случайный вектор высоты 4: In[197]:= nnn=4;aaa=rama[nnn,nnn];bbb=cora[nnn]; Вот так выглядит типичный получающийся при этом результат: a = 66 −83 1 63 −25 −10 −49 99 74 74 −31 −6 −92 62 44 70 , b = 13 19 −79 −8 . Определитель такой случайной целочисленной матрицы грандиозен (на- пример, в данном случае он равен 123258840). Поэтому применение коман- ды LinearSolve дает In[198]:= LinearSolve[aaa][bbb] Out[198]= {-1056071/2054314,-3961079/6162942, -597458/3081471,-202933/2054314 } В то же время команда NullSpace возвращает какую-то фундаменталь- ную систему решений уравнения ax = 0. Вот, к примеру, что получается 140 при применении этой команды к уже встречавшейся нам в предыдущем параграфе матрице test[4]: In[199]:= NullSpace[test[4]] Out[199]= {{-1,0,0,1},{-1,0,1,0},{-1,1,0,0}} Часто хочется увидеть общее решение неоднородной системы, совмеща- ющее ее частное решение и общее решение соответствующей неоднород- ной системы. Для этого нужно свести вместе результаты работы команд LinearSolve и NullSpace. Традиционную форму такого общего решения можно породить, например, при помощи следующей конструкции: In[200]:= gensolution[g ,b ]:=StringForm["``+``", MatrixForm[LinearSolve[g,b]], Table[a[i], {i,1,Length[NullSpace[g]]}]. Map[MatrixForm,NullSpace[g]]] Здесь использована одна из важнейших команд форматирования вывода StringForm. Мы часто пользуемся этой командой в тех случаях, когда нам нужно включить результат вычисления в текст. Эта команда служит для включения результатов вычисления в текстовый объект и вызывается в следующем формате: StringForm["ccc``ccc``ccc...",expression1,expression2,...] где, как мы уже знаем, заключенный в двойные кавычки "..." объект рас- сматривается как стринг, ccc обозначает произвольную комбинацию зна- ков, а каждая пара аксанов `` заменяется на значение очередного выра- жения expression. Теперь вычисление In[201]:= gensolution[test[4], {1,1,1,1}] даст нам следующий результат 1 0 0 0 + a 1 −1 0 0 1 + a 2 −1 0 1 0 + a 3 −1 1 0 0 . • Умножение матриц. В отличие от покомпонентного умножения * или, в полной форме Times, обычное матричное умножение представля- ющее композицию линейных отображений, обозначается . или, в полной форме Dot. Таким образом, x.y или Dot[x,y] выражает произведение мат- риц x и y. Например, In[202]:= {{a,b},{c,d}}.{{e,f},{g,h}} Out[202]= {{a*e+b*g,a*f+b*h},{c*e+d*g,c*f+d*h}} Чтобы проиллюстрировать матричные вычисления на содержательном примере, свяжем с каждой функцией f матрицу Тэйлора: In[203]:= taylor[f ,x ,n ]:= 141 Table[If[i<=j,D[f, {x,j-i}]/(j-i)!,0],{i,1,n+1},{j,1,n+1}] Взглянем на матрицу Тэйлора степени 5 — с точки зрения анализа, где нумерация производных начинается с нуля, эта матрица является матрицей Тэйлора порядка 4: T (f, 4) = f (x) f ′ (x) f ′′ (x)/2 f ′′′ (x)/6 f ′′′′ (x)/24 0 f (x) f ′ (x) f ′′ (x)/2 f ′′′ (x)/6 0 0 f (x) f ′ (x) f ′′ (x)/2 0 0 0 f (x) f ′ (x) 0 0 0 0 f (x) Вычислим теперь произведение двух матриц Тэйлора: In[204]:= Simplify[taylor[f[x],x,4].taylor[g[x],x,4]]//MatrixForm Мы не воспроизводим результат этого вычисления ввиду его громоздкости, но у каждого, кто когда-нибудь видел формулу Лейбница дифференциро- вания произведения, в этот момент закрадываются сильные подозрения. После следующего вычисления In[205]:= Timing[Simplify[ taylor[f[x],x,50].taylor[g[x],x,50]]== taylor[f[x]*g[x],x,50]] Out[205]= {3.034,True} эти подозрения незамедлительно переходят в уверенность. В самом деле, две матрицы степени 51 не могут совпасть по случайной причине! Это зна- чит, что от нас в курсе анализа скрывали нечто весьма существенное, а именно то, что многочлен Тэйлора n-го порядка произведения двух функ- ций равен произведению их многочленов Тэйлора того же порядка: T (f g, n) = T (g, n)T (g, n). Разумеется, многочлен Тэйлора n-го порядка следует здесь понимать с точностью до бесконечно малых более высокого порядка или, как сказал бы алгебраист, по модулю x n+1 То, что мы сейчас увидели — это как раз типичный пример грамотного использования Mathematica. А именно, опытный пользователь спрашивает у системы то, что он действительно хочет узнать, в данном случае, равна ли матрица Тэйлора функции f g произведению матриц Тэйлора функций f и g. Но для этого совершенно не обязательно фактически смотреть на сами эти матрицы или их произведение!! Неумелое использование, кото- рым грешат не только начинающие, но и многие авторы учебных текстов, состоит в том, чтобы показывать то, что с точки зрения окончательной це- ли является промежуточным результатом. Например, выводить на экран матрицу taylor[f[x],x,50].taylor[g[x],x,50]. • Обращение матриц. Обратная к g матрица g −1 вычисляется при помощи функции Inverse. Прежде всего проверим, что мы правильно понимаем, в каком формате вызывается Inverse: 142 In[206]:= Inverse[ {{a,b},{c,d}}] Out[206]= {{d/(-b*c+a*d),-b/(-b*c+a*d)}, {-c/(-b*c+a*d),a/(-b*c+a*d)}} Проиллюстрируем теперь использование этой функции на содержатель- ном примере. Следующая трехдиагональная матрица является одной из самых знаменитых и важных в математике. Чистым математикам она из- вестна как матрица Картана 45 , а прикладным — как матрица конеч- ных разностей 46 : In[207]:= cartan[n ]:=Table[Which[i==j,2,Abs[i-j]==1,-1,True,0], {i,1,n},{j,1,n}] Обратите внимание на использование для задания этой матрицы условно- го оператора Which. Встречавшийся нам ранее оператор If[test,x,y,z], выбирает одну из трех возможностей x, y, z в зависимости от трех значений истинности теста test, в следующем порядке: True, False, Undecided. В отличие от него оператор Which вызывается в формате Which[test1,x1,test2,x2,test3,x3,...] Этот оператор поочередно оценивает истинность каждого из тестов test1, test2, test3, ... и возвращает xi для первого из них, который принимает значение True. В нашем примере последний тест всегда выдает значение True, так что коэффицент матрицы в позиции (i, j) равен 0, если пара (i, j) не проходит ни одного из предыдущих тестов. Примерно так же работает и переключатель Switch, но, в отличие от условного оператора Which, он вызывается в другом формате и проверяет не прохождение теста, а сов- падение выражения с одной из предписанных форм или его соответствие предписанному паттерну. Так, скажем, Switch[Mod[i-j,4],0,a,1,b,2,c,3,d] принимает значение a, b, c или d в соответствии с тем, чему равен вычет i − j по модулю 4. Посмотрим для примера на матрицу cartan[8]: −2 −1 0 0 0 0 0 0 −1 2 −1 0 0 0 0 0 0 −1 2 −1 0 0 0 0 0 0 −1 2 −1 0 0 0 0 0 0 −1 2 −1 0 0 0 0 0 0 −1 2 −1 0 0 0 0 0 0 −1 2 −1 0 0 0 0 0 0 −1 2 45 Н.Бурбаки, 46 Р.Грегори, Е.Кришнамурти, Безошибочные вычисления. Методы и приложения. — М., Мир, 1988, с.1–208. 143 Обратная к этой матрице хорошо известна и очень часто используется. Изобразим для примера 9*Inverse[cartan[8]]: 8 7 6 5 4 3 2 1 7 14 12 10 8 6 4 2 6 12 18 15 12 9 6 3 5 10 15 20 16 12 8 4 4 8 12 16 20 15 10 5 3 6 9 12 15 18 12 6 2 4 6 8 10 12 14 7 1 2 3 4 5 6 7 8 • Определитель матрицы. Определитель матрицы g вычисляется при помощи функции Det. Как всегда, прежде всего стоит проверить на совсем простом примере, правильно ли мы понимаем ее использование: In[208]:= Det[ {{a,b},{c,d}}] Out[208]= -b*c+a*d Обратимся теперь к более интересным примерам. Мы уже говорили, что теория определителей была придумана для анализа единственного при- мера — определителя Вандермонда det(V (x 1 , . . . , x n )). Так вот с него и начнем. Вычисление Length[Det[vandermonde[y,5]]] показывает, что Ma- thematica считает, что этот определитель является суммой 120 слагаемых — как в этом мире все тяжело, все горести полно!!! 47 Однако при- меняя к тому же определителю команду Simplify, мы получим уже вполне осмысленный результат: In[209]:= Simplify[Det[vandermonde[y,5]]] Out[209]= (y[1]-y[2])*(y[1]-y[3])*(y[2]-y[3])*(y[1]-y[4])*(y[2]-y[4])* (y[3]-y[4])*(y[1]-y[5])*(y[2]-y[5])*(y[3]-y[5])*(y[4]-y[5]) Команда Minors[x] порождает все дополнительные миноры матри- цы x. Однако упорядочивает она их лексикографически по порядку вклю- ченных в них строк и столбцов (а вовсе не исключенных, как это делается в элементарных учебниках линейной алгебры!) Следующее вычисление по- казывает дополнительные миноры в матрице степени 3: In[210]:= fancy1=Partition[CharacterRange["a","i"],3] Out[210]= {{a,b,c},{d,e,f},{g,h,i}} In[211]:= Minors[fancy1] Out[211]= {{-b*d+a*e,-c*d+a*f,-c*e+b*f}, {-b*g+a*h,-c*g+a*i,-c*h+b*i}, {-e*g+d*h,-f*g+d*i,-f*h+e*i}} Обратите внимание на то, как мы порождаем матрицу степени 3: 47 “Deus,” dist li reis, “si penuse est ma vie!!!” — La chanson de Roland. 144 ◦ Команда CharacterRange["a","i"] генерирует список из 9 букв, лежа- щих между a и i, включительно. Отметим необходимость использования здесь кавычек! Эти кавычки означают, что a и i должны трактоваться не как символы, а как стринг, т.е. текстовые объекты, воспринимаемые verbatim. Большинство обычных команд трактует стринг как сырой объ- ект и не проводит с ним никаких вычислений. Имеются специальные тек- стовые команды, которые позволяют проводить со стрингами все обычные манипуляции, аналогичные обычным манипуляциям со списками. ◦ Команда Minors[x,m] порождает все миноры порядка m матрицы x, в лексикографическом порядке. In[212]:= fancy2=Partition[CharacterRange["a","p"],4] Out[212]= {{a,b,c,d},{e,f,g,h},{i,j,k,l},{m,n,o,p}} Теперь вычисление In[213]:= Minors[fancy2,2] дает следующий результат: −be + af −ce + ag −de + ah −cf + bg −df + bh −dg + ch −bi + aj −ci + ak −di + al −cj + bk −dj + bl −dk + cl −bm + an −cm + ao −dm + ap −cn + bo −dn + bp −do + cp −fi + ej −gi + ek −hi + el −gj + fk −hj + fl −hk + gl −fm + en −gm + eo −hm + ep −gn + fo −hn + fp −ho + gp −jm + in −km + io −lm + ip −kn + jo −ln + jp −lo + kp • Собственные числа и векторы. Собственные числа матрицы ищут- ся при помощи команды Eigenvalues, а соотвествующие им собственные векторы — при помощи команды Eigenvectors. Их можно найти одновре- менно при помощи команды Eigensystem. В следующем вычислении мы предлагаем системе вычислить собствен- ные числа и собственные векторы матрицы Фибоначчи 1 1 1 0 : In[214]:= Eigensystem[ {{1,1},{1,0}}] Out[214]= {{1/2*(1+Sqrt[5]),1/2*(1-Sqrt[5])}, {{1/2*(1+Sqrt[5]),1},{1/2*(1-Sqrt[5]),1}}} Уже нахождение собственных чисел и векторов целочисленных 3 × 3- матриц может быть нетривиальной вычислительной проблемой. Одним из интереснейших примеров является матрица кубического золотого сечения 48 3 2 1 2 2 1 1 1 1 Функция CharacteristicPolynomial вычисляет характеристический мно- гочлен матрицы: 48 В.И.Арнольд, Что такое математика? — М., МЦНМО, 2004, с.1–104; с.99. 145 In[215]:= CharacteristicPolynomial[ {{3,2,1},{2,2,1},{1,1,1}},x] Out[215]=1-5*x+6*x^2-x^3 Однако, как мы уже видели в § 3, корни этого многочлена выглядят доста- точно хитро. • Функции от матриц. Начинающий должен быть особенно осторо- жен в том, что касается функций, вычисление которых зависит от исполь- зуемого умножения. Дело в том, что большинство обычных функций по умолчанию используют покомпонентное умножение Times, называемое в теории матриц умножением по Адамару или умножением по Шуру. В то же время, для правильного вычисления функций от матриц необходимо всю- ду использовать обычное матричное умножение Dot. Классическая теория Кэли—Сильвестра—Фробениуса функций от матриц как раз и основана на том, что для диагональных матриц эти два умножения совпадают. Переводя разговор в практическую плоскость, это значит, например, что для вычисления степени матрицы нужно использовать не функцию Power, а функцию MatrixPower, для вычисления экспоненты от матрицы — не функцию Exp, а функцию MatrixExp и т.д. Вот, например, вычисление экспоненты числа 1 + √ 2, выраженного це- лочисленной матрицей 1 2 1 1 : In[216]:= MatrixExp[ {{1,2},{1,1}}] Out[216]= {{1/2*E^(1-Sqrt[2])*(1+E^(2*Sqrt[2])), E^(1-Sqrt[2])*(-1+E^(2*Sqrt[2]))/Sqrt[2] }, {E^(1-Sqrt[2])*(-1+E^(2*Sqrt[2]))/(2*Sqrt[2]), 1/2*E^(1-Sqrt[2])*(1+E^(2*Sqrt[2])) }}} Интересно, что применение Simplify не упрощает это выражение, но вот применение FullSimplify дает In[217]:= FullSimplify[MatrixExp[ {{1,2},{1,1}}]] Out[217]= {{E*Cosh[Sqrt[2]],Sqrt[2]*E*Sinh[Sqrt[2]]} {E*Sinh[Sqrt[2]]/Sqrt[2],E*Cosh[Sqrt[2]]} • Приближенные вычисления. Все, что сказано выше об опасности приближенных вычислений, в еще большей степени относится к вычисле- ниям с матрицами. Дело в том, что большинство алгоритмов используемых для этих вычислений по самой природе итеративны, что приводит к воз- никновению артефактов — а часто и просто чудовищных ошибок — уже для матриц небольшого порядка. В том же, что касается матриц порядка несколько тысяч или несколько десятков тысяч, приближенные вычисле- ния без надежного контроля точности и устойчивости вычислений являют- ся сплошным обманом зрения. В качестве подтверждения этого процитируем знаменитый пример Фор- сайта forsythe=forwaa[10]+10^(-10)*e[10,10,1] 146 Матрица Форсайта 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 10 −10 0 0 0 0 0 0 0 0 0 отличается от жордановой клетки J 10 (0) лишь в одной позиции, при этом значение элемента в этой клетке довольно мало, 10 −10 . В то же время собственные числа этой матрицы по модулю равны 10 −1 и, таким обра- зом, уже весьма заметно ненулевые! Жорданова форма матрицы forsythe имеет вид diag(e 1 /10, . . . , e 10 /10), где e 1 , . . . , e 10 — корни 10-й степени из 1. Невооруженным глазом вид- но, насколько эта жорданова форма отличается от жордановой матрицы J 10 (0). Этот пример служит замечательной иллюстрацией вычислительной неустойчивости канонических форм. Еще эффектнее выглядит вычисление обратной матрицы Inverse[forsythe]: 0 0 0 0 0 0 0 0 0 10000000000 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Ясно, что при рассмотрении матриц степени 1000 подобных эффектов мож- но достичь изменением одного элемента на 10 −1000 Вычислительная линейная алгебра уже более столетия развивает специ- альные приемы для борьбы с такого рода явлениями: масштабирование, изучение обусловленности, контроль ошибок. Однако для большинства практически встречающихся случаев самым простым и надежным лекар- ством является полный отказ от приближенных вычислений. 147 МОДУЛЬ 2. Основы синтаксиса Слуха нашего достигло, о чем мы и выговорить не можем без сты- да, что ты растолковываешь грамматику кое-кому из своих друзей. Папа Григорий Великий Описываемая в нашем учебнике система Mathematica является систе- мой компьютерной алгебры общего назначения, при помощи кото- рой можно решать любой тип задач, в которых в той или иной форме встречается математика. При этом Mathematica наряду с Maple являет- ся единственной такой high-end 49 системой, которая настолько проста в использовании, что доступна школьникам и студентам младших курсов. Mathematica, как и любая система компьютерной алгебры, может изла- гаться с точки зрения • математика, • программиста, • пользователя. Пользователь интересуется этой системой не с точки зрения принципов ее работы, а как законченным программным продуктом для проведения прак- тических вычислений в конкретной предметной области, скажем, в матема- тике, физике, информатике, технических науках, химии, астрономии, гео- логии, экономике, управлении, проектировании, архитектуре, лингвистике, компьютерной графике, музыке и т.д. При этом он совершенно не обязан понимать ни математических основ работы системы, ни используемых в ней алгоритмов, ни собственно программистских аспектов ее реализации, ее взаимодействия с платформой, операционной системой и другими про- граммами и других подобных вещей. Тем не менее, любой серьезный поль- зователь, который хочет использовать эти системы не просто в качестве редактора формул и большого научного калькулятора, любой грамотный пользователь, который хочет избежать хотя бы наиболее очевидных оши- бок и эффективно использовать возможности этих систем, должен пони- мать хотя бы основные принципы компьютерной алгебры, взаимоотноше- ние математической и вычислительной точек зрения и, в первую очередь, принятые в этих системах стандартные соглашения и специфику исполь- зуемого ими языка. Модуль 2 рассчитан как раз на такого серьезного пользователя, кото- рому и адресованы главы, посвященные основам синтаксиса языка Mathe- matica. Подобно другим системам компьютерной алгебры общего назна- чения Mathematica является в первую очередь языком программирова- ния сверхвысокого уровня. Отличие этих систем, в первую очередь 49 Словарь дает следующие переводы компьютерного термина high-end: мощный, профессиональный, высококачественный; высокого класса; с широкими функциональ- ными возможностями. Поскольку ни один из этих переводов не отражает всего пафоса и всех коннотаций оригинала, мы оставляем этот термин as is. 148 Axiom, Mathematica и Maple от традиционных языков программирования таких, как Fortran, Lisp, C, Pascal или Java состоит в том, что они со- держат в десятки раз больше командных слов и конструкций и по своей гибкости, выразительной силе и расширяемости приближаются к живым языкам. Поэтому изучать их надо так же, как учат иностранный язык, скажем, французский или греческий. Глава 4. ОБЪЕКТЫ И ВЫРАЖЕНИЯ Лейбниц говорил, что все бедствия людей от неумения ясно выра- жаться. Венедикт Ерофеев, Из записных книжек Для того, чтобы вычислить (evaluate) какое-то выражение, Mathema- tica должна быть в состоянии каким-то образом его интерпретировать. Всегда ли эта интерпретация совпадает с тем, что имел в виду автор, когда писал программу — это большой отдельный вопрос, к которому мы будем снова и снова возвращаться в следующих главах! Однако чтобы подлежать эвалюации выражение должно быть как минимум синтаксически коррект- ным, т.е. полным и правильно составленным. В этой части мы как раз и опишем некоторые простейшие правила построения корректных вы- ражений и основные способы внутреннего представления данных в самой системе. При этом вводятся важнейшие понятия языка Mathematica та- кие, как тип объекта, имя объекта, домен, символ, число, переменная, значение, присваивание, подстановка и т.д., а также некоторые наиболее употребительные команды. В следующих главах мы определим дальней- шие ключевые понятия: функция, аргумент, параметр, опция, атрибут, оператор, предикат, отношение, паттерн, список, последовательность, стринг и т.д. Однако даже из этих наиболее фундаментальных понятий, простейших правил и важнейших команд для использования Mathema- tica качестве калькулятора необходима лишь небольшая часть. Поэтому тот, кто интересуется системой Mathematica главным образом для решения школьных или вузовских задач по математике, может при первом чтении пропускать все непонятные или более технические места, возвращаясь к ним потом по мере необходимости!!! Самое главное — двигаться вперед, потому что математика становится понятной только при взгляде назад: Mathematica is only learned in hindsight!!! 149 § 1. Выражения: FullForm, Head, Part, Level, Length, Depth Everything is an expression. Steven Wolfram Прежде, чем начинается вычисление, любой ввод, который Вы печатае- те, должен быть интерпретирован ядром системы Mathematica как выра- жение (expression). Каждое выражение имеет жесткую иерархическую структуру, описывающую из каких объектов оно состоит, как и в каком по- рядке они соединяются в подвыражения (subexpressions) и т.д. Преж- де всего, каждое выражение x имеет заголовок Head[x], указывающий, к какому классу оно относится, с чего начинается его вычисление и какие алгоритмы при этом применяются. Заголовок выражения может быть • функцией: Exp, Log, Cos, Sin и т.д., • командой: Expand, Factor, Plot, Play и т.д., • оператором: Plus, Times, Power, Equal и т.д., • типом объекта: Integer, Rational, Real, Complex, Symbol, String, List, SparseArray, Graphics, SurfaceGraphics, Graphics3D, Sound и т.д. Впрочем, приведенные различия являются психологическими и лингвисти- ческими, а не вычислительными. Они относятся скорее к интерпретации проделываемых операций, чем к их внутреннему представлению или тому, как система работает с ними. Например, термин функция подразумевает, что проделывается нечто с рассматриваемыми математическими объекта- ми, в то время как команда меняет не сами эти объекты, а форму их записи или, в случае если эти объекты сами являются функциями или команда- ми, режим (modality) их работы или, наконец, состояние самой системы. Удивительная особенность системы Mathematica, которая вначале кажется странной, но после приобретения некоторого опыта становится в высшей степени удобной, состоит в том, что с ее точки зрения тип List объекта List[x 1,...,x n] ничем не отличается от функции, объединяющей n ар- гументов x 1 , . . . , x n в список {x 1 , . . . , x n }, или команды, предписывающей это сделать. А различие между функцией и оператором вообще относит- ся только к традиционной форме записи и не имеет никакого судьбонос- ного значения уже в самой математике. Поэтому серьезные пользователи даже не пытаются задумываться над тем, является ли встроенный объект Blabla функцией или командой и используют эти слова как синонимы. В качестве атомарных объектов, не имеющих дальнейшей внутренней структуры, Mathematica рассматривает • число (целое, рациональное, вещественное или комплексное), • символ (объект вычислений, определяемый своим именем), • стринг (текстовый объект, воспринимаемый verbatim). Атомарный объект тоже имеет заголовок, выражающий его тип, но не име- ет никаких дальнейших частей. Аналогией этой ситуации является теория 150 множеств с праэлементами, где каждый объект является либо мно- жеством имеющим элементы (= выражение, имеющее части), либо пра- элементом, не имеющим элементов (= выражение, не имеющее частей). Перечислим заголовки атомарных типов Integer целое число Rational рациональное число Real вещественное число Complex комплексное число Symbol символ String текстовая строка Как мы уже упоминали, в ядре Mathematica определено много других ти- пов объектов и данных — List, SparseArray, Graphics, SurfaceGraphics, Graphics3D, Sound и т.д., но они имеют дальнейшую внутреннюю струк- туру, (во многих случаях чрезвычайно сложную!!!) Еще больше таких типов введено в пакетах расширения. Кроме того, опытный пользователь может вводить новые типы объектов и правила, по которым производятся операции над ними. Таким образом, каждая часть выражения, в свою очередь имеет заго- ловок, а те части, которые не являются атомарными объектами, кроме того, сами имеют части, являющиеся составляющими (constituents) исходного выражения. Однако, как и в теории множеств, часть части не обязательно является частью исходного выражения (= отношение ∈ нетранзитивно). Части частей исходного выражения вложены в него на уровне 2 или на глубине 2. Нюанс здесь состоит в том, что один и тот же объект может входить в выражение на разных уровнях, например, x входит в множество {x, {x}} как на уровне 1 (как элемент), так и на уровне 2 (как элемент элемента)! Кроме того, в отличие от теории множеств теперь чрезвычайно важно, сколько раз и в каких позициях каждая составляющая входит в выражение. В свою очередь части частей тоже являются либо атомарными объекта- ми, либо имеют дальнейшую структуру. В последнем случае про их части говорят, что они вложены в исходное выражение на уровне 3 или на глу- бине 3. В силу конечности процесс взятия частей должен оборваться, а оборваться он может только на атомарных объектах, это те составляющие, на которых невозможно дальнейшее движение вглубь, они называются ли- стьями (leaves) — в мире Mathematica деревья растут сверху вниз!! Лист является частью части ... части и глубина его вхождения определяется тем, сколько раз здесь повторено слово часть. Перечислим несколько команд, позволяющих увидеть, как на самом деле устроено выражение, каковы его заголовок, части, уровни и полная форма. Философский комментарий. Выражение на самом деле здесь относится к тому уровню сознания, на котором функционирует язык системы Mathematica. Разумеется на самом деле внутреннее представление данных в коде языка C и фактическое пред- ставление данных в памяти компьютера устроены как-то иначе и, в любом случае, еще 151 гораздо более детально. Но система Mathematica только потому и обладает интеллек- том, достаточным для проведения весьма сложных вычислений в режиме диалога, а не процедуры, что на сознательном уровне она не имеет доступа к этим более низким уровням мышления. Здесь мы обсуждаем представление данных на внутреннем языке Mathematica, не зависящее от платформы и программной реализации, иными словами, внутренние, а не системные феномены. Итак, вот основные команды, позволяющие анализировать структуру выражений, в простейшем виде. В дальнейшем мы обсудим дальнейшие спецификации параметров в этих командах, которые позволят видеть боль- ше и/или иначе. FullForm[x] полная форма выражения x TreeForm[x] иерархическая структура выражения x Head[x] заголовок выражения x Part[x,n] n-я часть выражения x Length[x] длина выражения x, не считая заголовка Depth[x] глубина выражения x, считая заголовок Level[x, {n}] составляющие выражения x на уровне n Level[x,n] составляющие выражения x на уровнях ≤ n AtomQ[x] вопрос, является ли x атомарным объектом Опишем, что делают эти команды. Использование функций Head[x], Length[x] и Depth[x] ясно без всяких дальнейших объяснений, нужно только помнить, что по умолчанию (Heads->False) команда Length не включает заголовок, являющийся нулевой частью выражения x в под- счет частей, а вот команда Depth включает нулевой уровень (состоящий из заголовка выражения x) в его глубину. Вот что делают остальные ко- манды: • FullForm[x] дает полную форму выражения x в функциональной записи, где расшифрованы все сокращения, расставлены все необходимые скобки, произведены все подстановки, после чего составляющие отсортиро- ваны в стандартном порядке (обычно численном и/или алфавитном). • TreeForm[x] — практически то же самое, что FullForm[x] но, кроме того, выражение явным образом графически разделено на уровни, показы- вающие глубину вхождения составляющих. • Part[x,n] или, сокращенно, x[[n]] — часть выражения x с номером n. Выражение Part[x,n] имеет смысл только для 0<=n<=Length[x], если Вы попробуете выделить n-ю часть выражения x для n>Length[x], систе- ма выдаст сообщение об ошибке. По определению Part[x,0]===Head[x]. Мы подробно опишем действие команд Part[x,m,n], Part[x, {m1,...mr}], Part[x, {m1,...mr},{n1,...,ns}], а также альтернативный способ извле- чения частей Extract[x, {i,j}] в § 2 Главы 8. • Level[x,{n}] порождает список составляющих выражения, лежащих на уровне n, а Level[x,n] — список всех составляющих на уровнях от 1 до n. По определению Level[x, {0}]==={x} и Part[x,0]==={}. В § 2 Главы 8 152 мы более обстоятельно опишем детализацию уровней (level specifica- tion) в этой и других подобных командах. § 2. Что такое квадратный трехчлен? В качестве простейшего примера изложенной в предыдущем параграфе теории проанализируем внутреннее представление квадратного трехчлена f = ax 2 + bx + c. Вот что на самом деле ядро программы Mathematica понимает под квадратным трехчленом и вот с чем происходит вычисление: In[1]:=f=a*x^2+b*x+c; FullForm[f] Out[1]=Plus[c,Times[b,x],Times[a,Power[x,2]]] Посмотрим вначале на ввод: в нем встречаются три специальных символа +, ∗ и ˆ, используемых при сокращенной инфиксной записи алгебраи- ческих операций сложения, умножения и возведения в степень, см. по этому поводу § 6 Главы 6. В палитре BasicCalculations можно вводить значки всех этих операций в традиционной форме, наподобие того, как это де- лается в MathCad, как знак умножения и верхний индекс, однако с нашей точки зрения это абсолютно бессмысленно, так как ввод с клавиатуры зна- чительно быстрее, чем шуршание мышкой по палитрам. Посмотрим теперь вывод: Mathematica считает, что мы предложили ей сложить три вещи: атомарный объект c, который не имеет никакой дальнейшем структуры (на момент вычисления является символом), произведение атомарного объекта b на атомарный объект x и еще одну вещь, которая тоже устроена как произведение. Однако это второе произведение имеет дальнейшую структуру, так как только первый множитель является атомарным объек- том, в то время как второй в свою очередь является результатом возведения атомарного объекта x в степень 2. С другой стороны, команда TreeForm порождает вывод наподобие сле- дующего, явным образом показывающий, на каком уровне вложены под- выражения: In[2]:=TreeForm[f] Out[2]=Plus[c | , | ] Times[b,x] Times[a, | ] Power[x,2] Обратите внимание, что мы не повторяли определение f . Если это происхо- дит в той же сессии, в которой мы спрашивали про полную форму f , мы мо- жем не вводить определение f второй раз, так как система его помнит. Для опытного пользователя, умеющего мгновенно не включая сознание считать скобки до седьмого уровня, эта форма представления выражения не содер- жит ничего нового по сравнению с полной формой. Однако начинающий должен отметить для себя несколько моментов, например, то, что на каж- дом уровне закрывается такое же количество скобок, сколько открывается. В действительности, это является одной из важнейших характеристик пра- вильно составленного выражения. В частности, мы видим, что внутреннее 153 представление многочлена ax 2 +bx+c состоит из трех уровней — плюс, ко- нечно, заголовок Plus: спросите у системы, верно ли, что Head[f]===Plus? Таким образом, общая глубина этого выражения, включая заголовок , рав- на 4, Depth[f]===4. Посмотрим теперь еще раз на части представляющего f выражения: In[3]:=Map[Part[f,#]&,Range[0,3]] Out[3]= {Plus,c,b*x,a*x^2} Мы видим, что это выражение состоит из заголовка Plus и трех частей c, b*x и a*x^2. Это значит, что Length[f]===3. В предыдущем диалоге мы использовали несколько команд, а именно, Map, Function (в сокращенной записи, использующей специальные знаки # и &) и Range, которые нам до сих пор не встречались. Эти команды подробно описаны в Главе 6, но в действительности они использованы здесь только для сокращения. Эта строка предлагает программе подставить в выражение Part[f,i] вместо i поочередно все четыре элемента множества Range[0,3]=== {0,1,2,3}. Мы могли бы с таким же успехом напечатать более наивный текст, скажем, In[4]:= {Part[f,0],Part[f,1],Part[f,2],Part[f,3]} и получили бы точно такой же результат. Фигурные скобки здесь нужны для того, чтобы система показала нам все четыре результата одновременно. Без этих фигурных скобок она выдала бы нам сообщение о синтаксической ошибке, либо, если бы мы придали этой строке синтаксически правильную форму, заменив все запятые на точки с запятой, отобразила бы на экране только результат последнего вычисления, а не всех четырех вычислений! А вот как работает команда Level[f, {x}]. Посмотрим на уровни мно- гочлена f с нулевого по четвертый: In[4]:=Map[Level[f, {#}]&,Range[0,4]] Out[4]= {{c+b*x+a*x^2},{c,b*x,a*x^2},{b,x,a,x^2},{x,2},{}} Как и в предыдущем случае, мы могли бы породить тот же ответ без всяких там Map и Function, при помощи следующего незамысловатого текста: In[5]:= {Level[f,{0}],Level[f,{1}],Level[f,{2}], Level[f, {3}],Level[f,{4}]} А вот как действует Level[f,n] с указанием уровня без фигурных скобок, при этом каждый следующий список включает все предыдущие: In[5]:=Map[Level[f,#]&,Range[0,4]] Out[5]= {{},{c,b*x,a*x^2},{c,b,x,b*x,a,x^2,a*x^2}, {c,b,x,b*x,a,x,2,x^2,a*x^2} Упражнение. Проделайте то же самое для многочленов степени 4 или 5, и посмотрите на их реализацию как выражений на внутреннем языке системы Mathematica, их части и уровни. Кстати, это упражнение будет полезно начинающему и как практика во вводе синтаксически правильного текста с клавиатуры! 154 Переведем этот ответ на более привычный язык. Разумеется, то же самое относится не только к многочленам степени 2, но и вообще ко всем многочленам f = a n x n + . . . + a 1 x + a 0 ◦ на нулевом уровне лежит сам многочлен f; ◦ на первом уровне — составляющие его одночлены a i x i , включая сво- бодный член a 0 ; ◦ на втором уровне — коэффициенты a i — кроме свободного члена, уже посчитанного на первом уровне! — и нормированные одночлены, кроме 1, которая автоматически втягивается в свободный член; ◦ на третьем уровне — переменная x и показатели степени ≥ 2, с кото- рыми она входит в нормированные одночлены (Power[x,0] даже если мы задавали бы многочлен в такой форме, автоматически упрощается до 1, а Power[x,1] — до x, так что они до этого уровня не доживают); ◦ на четвертом уровне (и, тем самым, на более глубоких уровнях!) нет вообще ничего, что, впрочем, не удивительно, так как глубина f равна 4, считая нулевой уровень. Это показывает, насколько язык системы Mathematica близок к струк- турному математическому мышлению! В качестве составляющих много- члена естественно возникли одночлены, нормированные одночлены, коэф- фициенты, неизвестная и показатели степени, то есть как раз все те поня- тия, которые используются при математическом описании многочленов! Эта ситуация в высшей степени типична!! Нет ничего более полезного для эффективной организации вычислений в любой области, чем понимание математической структуры рассматриваемых понятий, а язык систе- мы Mathematica абсолютно сознательно структурирован в том духе, как это принято в современной математике. § 3. Выделение уровней Ты, Петька, прежде чем о простых вещах говорить, разберись со сложными. Виктор Пелевин. Чапаев и Пустота В § 1 мы уже упоминали о различных способах выделения уровня. Сей- час мы расскажем всю правду. Level[x,levelspec] уровни выражения x, описываемые levelspec n верхние n уровней выражения -n нижние n уровней выражения {n} только n-й уровень выражения {-n} только n-й уровень выражения снизу {m,n} уровни выражения между m и n Infinity все уровни выражения 155 Использование положительных спецификаций уровня уже обсуждалось выше и понятно само по себе. В качестве еще одного примера рассмот- рим вложенный список (nested list): alist= {a,{b,{c,{d,{e,{f}}}}}}. Вот уровни этого выражения с 1-го по 7-й In[6]:=Map[Level[alist, {#}]&,Range[1,7]] Out[6]= {{{a,{b,{c,{d,{e,{f}}}}}}, {b,{c,{d,{e,{f}}}}}, {c,{d,{e,{f}}}}, {d,{e,{f}}}, {e,{f}}, {f}, {}} Чуть труднее понять использование отрицательных уровней. Отрица- тельная спецификация уровня -n выделяет все составляющие выражения, которые имеют глубину n. Напомним, что по умолчанию заголовок выра- жения включается в его глубину, так что глубина атома равна 1. Кроме того, во избежание недоразумений еще раз подчеркнем, что речь идет не о тех составляющих, которые лежат на глубине n в исходном выражении, а о тех, которые сами имеют глубину n!!! Таким образом, например, Level[x, {-1}] дает список всех листьев вы- ражения x, т.е. всех входящих в x атомов. Точно так же Level[x, {-2}] даст список всех составляющих глубины 2, т.е. тех составляющих, которые сами не являются атомами, но вот всех их части уже являются атомами, и т.д. Вот уровни alist с −1-го по −7-й: In[7]:=Map[Level[alist, {-#}]&,Range[1,7]] Out[7]= {{a,b,c,d,e,f}, {{f}}, {{e,{f}}}, {{d,{e,{f}}}}, {{c,{d,{e,{f}}}}}, {{b,{c,{d,{e,{f}}}}}}, {{a,{b,{c,{d,{e,{f}}}}}}}} По умолчанию уровни не включают заголовки выражений, иначе говоря, дефолтной установкой опции Heads является False. Однако эту установку можно перебороть, установив Heads->True: In[8]:=Level[alist, {-1},Heads->True] Out[8]= {List,a,List,b,List,c,List,d,List,e,List,f} Спецификация уровня {m,n} включает в себя все уровни выражения между m-м и n-м, включительно. Так, например, Level[x, {2,-2}] опи- сывает все составляющие, кроме частей и листьев выражения x: In[9]:=Level[alist, {2,-2}] Out[9]= {{f}, {e,{f}}, {d,{e,{f}}}, {c,{d,{e,{f}}}}} Кроме функции Level многие другие важнейшие функции, в особенно- сти функции работы со списками, функционального программирования и некоторые отношения, используют спецификацию уровня. К этим функци- ям относится, в частности, Apply, Cases, Count, FreeQ, Map, MapIn- dexed, MapThread, Position, Replace, Scan. Для того, чтобы грамот- но использовать эти и другие подобные им функции, исключительно важ- но помнить, что по умолчанию они используют различные спецификации уровня!!! 156 Рассмотрим в качестве примера две важнейшие команды применения функции к спискам, Apply и Map. Каждая из них может применяться к выражению на любом уровне. В качестве примера применим к alist функцию g вначале при помощи команды Apply на уровнях с 1-го по 6-й, а потом при помощи команды Map на уровнях с 1-го по 7-й: In[10]:=Map[Apply[g,alist, {#}]&,Range[0,6]] Out[10]= {g[a,{b,{c,{d,{e,{f}}}}}], {a,g[b,{c,{d,{e,{f}}}}]}, {a,{b,g[c,{d,{e,{f}}}]}},{a,{b,{c,g[d,{e,{f}}]}}}, {a,{b,{c,{d,g[e,{f}]}}}}, {a,{b,{c,{d,{e,g[f]}}}}}, {a,{b,{c,{d,{e,{f}}}}}}} In[11]:=Map[Map[g,alist, {#}]&,Range[0,7]] Out[11]= {g[{a,{b,{c,{d,{e,{f}}}}}}], {g[a],g[{b,{c,{d,{e,{f}}}}}]}, {a,{g[b],g[{c,{d,{e,{f}}}}]}}, {a,{b,{g[c],g[{d,{e,{f}}}]}}}, {a,{b,{c,{g[d],g[{e,{f}}]}}}},{a,{b,{c,{d,{g[e],g[{f}]}}}}}, {a,{b,{c,{d,{e,{g[f]}}}}}}, {a,{b,{c,{d,{e,{f}}}}}}} Применение g на более глубоких уровнях как при помощи Apply, так и при помощи Map бессмысленно, так как мы видим, что начиная с уровня 6 для Apply, и начиная с уровня 7 для Map выражение перестает меняться. Однако если применить g к alist при помощи Apply и Map без указания уровня, то по умолчанию Apply применяется к выражению в целом, т.е. на уровне 0, а Map — к частям выражения , т.е. на уровне 1. Таким образом, вычисление Apply[g,alist] даст g[a, {b,{c,{d,{e,{f}}}}}], иными словами, заголовок List выражения alist заменяется на g. С другой стороны, вычисление Map[g,alist] даст {g[a],g[{b,{c,{d,{e,{f}}}}}], т.е. g применяется к обеим частям выражения alist. § 4. Имена объектов Как вы яхту назовете, так она и поплывет. Христофор Бонифатьевич Врунгель С точки зрения подавляющего большинства пользователей в Mathema- tica встречаются имена трех форматов: • Aaaa — имена внутренних (Internal) объектов, • aaaa — имена объектов, определенных пользователем (user-de- fined), • $Aaaa — имена системных (System) объектов. Внутренние и системные объекты являются встроенными (BuiltIn). При этом внутренние объекты являются фактами языка, относящимися к вы- числению как таковому (как в математических, так и в алгоритмических аспектах), в то время как системные объекты описывают или модифициру- ют экстралингвистические факты: свойства компьютера и операционной системы, на которых фактически производится вычисление, взаимодей- ствие ядра Mathematica с твердыми и мягкими изделиями (hardware and software) и тому подобные вещи, внешние по отношению к собственно вычислению. В некоторых случаях нам хочется, чтобы способ выражения влиял на способ действия или, наоборот, возникает искушение включить в нашу прозу непосредственное обращение к действительности (время су- ток, тип компьютера, широту и долготу и т.д.). Это приводит к появлению 157 дуплетов типа MachinePrecision и $MachinePrecision. Впрочем, в боль- шинстве случаев никакой прямой связи между внутренними объектами и системными объектами с похожими именами нет: основной графический элемент Line не имеет ничего общего со спецификацией ввода $Line. На начальном этапе изучения языка следует полностью сосредоточиться на структурных вопросах и игнорировать существование внешнего мира. В настоящей книге мы будем описывать только вычисления, которые могут быть реализованы в терминах внутренних объектов языка Mathematica. Резюмируем основные правила образования имен: • В отличие от многих языков программирования заглавные (UpperСase) и строчные (LowerСase) буквы рассматриваются как различные. • Имя любого внутреннего объекта начинается с заглавной буквы. Имя любого системного объекта начинается с доллара $ (DollarSign), за ко- торым следует заглавная буква. • В случае, когда название внутреннего или системного объекта состоит из нескольких слов, каждое из них пишется с заглавной буквы. Никаких пробелов, дефисов и пр. внутри имени не ставится. В большинстве ситуаций пробел интерпретируется как знак умножения ∗. Таким образом x y обозначает произведение объектов x и y, а вовсе не новый объект с именем xy. Единственный специальный знак, который начинающий по аналогии с некоторыми другими языками программирования может интерпретировать как часть имени, это в составе такой конструкции как blabla pattern но в действительности этот знак вводит паттерны, т.е. указывает к какому классу принадлежит объект blabla • Имена внутренних и системных объектов являются либо полными ан- глийскими словами, либо стандартными математическими сокращения- ми, принятыми в англоязычной литературе. • Индивидуальные объекты, названные в честь своего изобретателя, как правило имеют имя формы PersonSymbol. Например, дельта Кронеке- ра будет называться KroneckerDelta, n-е число Каталана — CatalanNum- ber[n]. Однако в некоторых случаях это соглашение не соблюдается. Ска- жем, константа Каталана называется просто Catalan. • Имя объекта, определенного пользователем, может начинаться с лю- бой строчной буквы и содержать в своем составе заглавные и строчные буквы и цифры. При желании пользователь может определять и имена, начинающиеся с прописной буквы, но в этом случае нет никакой уверенности в том, что они не вступят в конфликт с какими-то именами объектов, встречающимися в пакетах. • Ни одно имя не может начинаться с цифры. Появляющееся в начале выражения число интерпретируется как коэффициент, а не часть имени. Например, 2x представляет удвоенное x, а вот x1, x2, x3 это одна из форм (далеко не самая удобная!!!) ввести переменные x 1 , x 2 , x 3 • Имя объекта не может содержать никаких специальных знаков таких как @, %, ˆ, &, #, / и т.д. Все эти знаки используются системой для специальных целей: сокращенной (“операторной”) записи функций, управления и форматирования ввода. 158 Вся правда 1. То, что мы сказали об именах объектов есть правда, но не вся правда. Блоки, модули и некоторые другие специальные команды порождают имена некоторых других форматов, скажем локальные и уникальные имена формата aaa$nnn. Однако знакомство с этими форматами предполагает некоторое понимание того, что реально происходит при работе программы и может понадобиться Вам только в тот момент, когда Вы реально начнете писать программы, исполнение которых требует много часов (или дней!) Любой юзер, работающий в диалоговом режиме, может прекрасно обходить- ся без этих вещей придумывая уникальные имена для своих переменных. Вся правда 2. С точки зрения профессионала (например, разработчика пакетов) имя объекта в языке Mathematica устроено примерно так же, как имя файла. В большинстве операционных систем допустимы файлы с одинаковыми именами, если они находятся в различных директориях. Иными словами, name.ext называемое в просторечии име- нем файла, является только частью его полного имени, включающего в себя путь от корневой директории: dir1 \dir2\...\dir17\name.ext Точно так же Name, которое до сих пор называлось именем объекта Mathematica, в дей- ствительности является только частью его полного имени. Настоящее имя объекта имеет форму Context`Name, где Context` представляет собой контекст. В свою очередь контекст может быть частью другого более широкого контекста и т.д.!!! Тем самым, в действительности полное имя объекта Name имеет вид Context1`Context2`...Context17`Name Это значит, что даже на протяжении одной сессии можно без всяких конфликтов исполь- зовать одно и то же имя для десятков различных объектов, если это имя встречается в различных контекстах . Переход в другой контекcт осуществляется командой Begin["Context`"], а возвраще- ние в начальный контекст командой End[]. Однако по умолчанию начинающий видит (в действительности, не видит!!!) только два контекста, System`, для встроенных объ- ектов, и Global`, для тех объектов, которые он определяет во время сессии. Исполь- зование контекстов становится по-настоящему важным только в тот момент, когда Вы либо профессионально занимаетесь написанием пакетов, которыми пользуются тысячи юзеров, либо решаете задачи в многопроцессорном режиме, для чего Вам приходится организовывать трубки для обмена данными между несколькими процессами, скажем, между несколькими работающими одновременно сессиями Mathematica. Однако и в том и в другом случае Вы вряд ли читаете эту книгу. Во всех остальных случаях Вам не представит труда придумать несколько сотен уникальных имен для определяемых Вами объектов. Даже если среди этих имен есть повторяющиеся, обычно легко избежать их использования на протяжении одной сессии. § 5. Группировка и скобки в математике |