Основы работы в системе компьютерной алгебры Mathematica

Программирование, основанное на правилах преобразований

Разбить на страницы
Показывать лекцию целиком

Цель лекции: познакомиться с принципами реализации стиля программирования, основанного на правилах преобразований, в языке программирования Mathematica

10.0. Введение

Как справедливо отмечает Е. М. Воробьёв [1, с. 140], понятие преобразования является одним из ключевых в математике. Большинство математических операций, математических объектов, так или иначе, связано с преобразованиями. Так таблицу умножения можно рассматривать как совокупность правил преобразований: согласно им мы с полным правом, не боясь условий и ограничений, можем заменить одно выражение, скажем, 3x3, другим — 9. Математические тождества также представляют собой правила преобразования: например, тождество $$(a+b)(a-b)=a^2-b^2$$ позволяет в математических расчётах заменить его правую часть левой или наоборот.

Операции математического анализа также не являются исключением. Основной задачей математического анализа является приведение выражений, содержащих суммы, интегралы, производные и т.д., к виду, в котором мы можем заменить их другими выражениями согласно справочным данным. Например, в процессе вычисления мы можем неопределённый интеграл от выражения $$cos^2(x)$$ по $$dx$$ заменить выражением $$(x+sin(x) cos(x))/2+const$$. Таким образом, объекты математического анализа также подчиняются правилам преобразования.

Помимо традиционных математических правил преобразования Mathematica имеет широкий набор средств для создания собственных правил. Именно на них и основывается рассматриваемый в настоящей лекции стиль программирования.

Программирование, основанное на правилах преобразования (rule-based programming), характеризуется преобразованием объектов данных различных типов (М. А. Марин и др. [10]). Преобразования есть суть вычисления; они описываются правилами замены одних объектов другими согласно некоторому шаблону. Программирование, основанное на правилах преобразования, является наиболее естественным для высокоорганизованного языка программирования Mathematica. Для ознакомления с данным стилем программирования воспользуемся логикой изложения, применённой в работе Е. М. Воробьёва [1].

10.1. Правила преобразования

10.1.1. Глобальные правила преобразования

Е. М. Воробьёв [1, с. 141] начинает знакомство читателей с правилами преобразований с уже известного нам простейшего правила — присвоения некоторого значения a символу x. С инфиксной формой немедленного присваивания мы познакомились в лекции 2 настоящего курса и знаем, что оно осуществляется при помощи знака " = ". Таким образом, выражение x=a означает, что во всех выражениях в тексте программы, содержащих x, его следует заменить выражением a. Поскольку замена осуществляется во всех выражениях программы, то правило преобразования, задаваемое немедленным присваиванием, является глобальным. Внутренней формой операции немедленного присваивания является функция Set[expr1,expr2]: она заменяет выражение expr1 выражением expr2. Е. М. Воробьёв [1, с. 141] так описывает процесс присваивания: "Выражение Set[expr1,expr2] вычисляется следующим образом. Аргумент expr1 вовсе не вычисляется, выражение expr2 вычисляется, и это вычисленное значение присваивается выражению expr1". Он также отмечает, что такой порядок выполнения функции не случаен и имеет строгое обоснование. Рассмотрим это утверждение на примере. Пусть мы задали выражение y=10, то есть, символу y присвоили значение 10. Затем нам понадобилось присвоить символу y новое значение, например, 5, для чего мы задали функцию Set[y,5]. Если бы при выполнении этой функции первый аргумент (y в нашем случае) вычислялся, то Mathematica бы решила, что мы хотим присвоить значение 5 числу 10, что граничит с разумным. Подобного парадокса и помогает избежать описанный алгоритм вычисления функции Set.

Примеры задания и использования глобального правила преобразования при помощи функции немедленного присваивания Set в инфиксной (In[1] и In[2]) и внутренней (In[3] и In[4]) форме см. на рис. 10.1.

(рис 10.1) Задание глобального правила преобразования при помощи функции Set

В примерах на рис. 10.1 мы присваивали выражения некоторым символам, хотя, в принципе в качестве выражения expr1, которому присваивается значение expr2, может выступать любое выражение. В примере In[1] на рис. 10.2 мы присвоили некоторой неопределённой функции f[x] значение 5, а в примере In[2] вычислили квадрат выражения f[x]: результат вычисления в Out[2] непосредственно связан с ранее присвоенным выражению численным значением 5.

Однако если мы попытаемся присвоить значение выражению, содержащему в теле некоторую встроенную функцию, например, Plus (пример In[3] на рис. 10.2), то нас постигнет неудача: значение не будет присвоено и Mathematica выдаст предупреждающее сообщение о том, что функция Plus обладает атрибутом Protected. Этот атрибут защищает выражение с данным заголовком от присваивания значений. И всё же даже выражениям с защищёнными заголовками значения могут быть присвоены. Для этого следует убрать из списка принадлежащих функции атрибутов атрибут Protected, применив к ней функцию Unprotect (пример In[4]). После этой процедуры никаких препятствий к присвоению значений не остаётся (примеры In[5] и In[6]). Похожую процедуру для функции Power описывает Е. М. Воробьёв [1, с. 144–145].

Однако Mathematica приписывает функциям атрибут Protected не из желания усложнить пользователю жизнь. Дело в том, что в процессе вычислений программе приходится иметь дело с большим числом правил преобразований. Поскольку большинство встроенных функций, таких, как Plus, Times, Power и др., используются при вычислении достаточно часто, то любое дополнительное правило преобразования, ассоциированное с ними, оказывает влияние на скорость вычислений и может значительно замедлить работу программы. Именно поэтому следует снова защитить такие функции от присваивания, если атрибут Protected однажды был убран из списка их атрибутов. Делается это, как не сложно предположить, при помощи функции Protect. Так в примере In[7] мы снова присваиваем функции Plus атрибут Protected, а в In[8] убеждаемся в том, что он присвоен, выведя на экран все атрибуты функции Plus.

Подробней об атрибуте Protected см. книгу Е. М. Воробьёва [1, с. 142, 144–145].

(рис 10.2) Присвоение значения выражению, защищённому атрибутом Protected

Существует ещё один способ присваивания значений защищённым выражениям — применение так называемых верхних значений. Этот способ позволяют ассоциировать правила преобразований с элементами, находящимися на первом уровне выражений: при этом совершенно не важно, является ли заголовок защищённым. Присваивание осуществляется функциями UpSet и UpSetDelay, инфиксные формы которых выглядят как " ^= " и " ^:= ", соответственно.

Для иллюстрации возможностей использования верхних значений приведём пример, аналогичный примеру в книге Е. М. Воробьёва [1, с. 145]. В In[1] на рис. 10.3 мы заменяем выражение p^q символом r. Теперь символ r ассоциирован с выражениями p и q и является их верхним значением, в чём мы убеждаемся в примерах In[2] и In[3], запрашивая сведения об этих выражениях. В примере In[4] на рис. 10.3 мы вводим некоторое выражение, содержащее p^q, и в результате вычислений Out[4] видим, что p^q действительно было заменено символом r.

В примере In[5] на рис. 10.3 мы попробуем присвоить верхнее значение t выражению s^2. К нашему удивлению, попытка совершить подобное действие терпит фиаско: Mathematica выдаёт сообщение о том, что защищённым является заголовок Integer, который, как мы знаем, отвечает за целочисленный тип данных. Заставить Mathematica осуществить присваивание в этом случае невозможно, поскольку правило преобразования можно ассоциировать с символами, и нельзя — с числами и строками. Однако и из этой, казалось бы, тупиковой ситуации есть выход. Можно присвоить верхнее значение выражению s^2, ассоциировав новое правило только с символом s в этом выражении. Делается это при помощи функции TagSet, инфиксная форма которой " /: " (примеры In[6] и In[7]). Поскольку в наших примерах s ассоциировано с t только в выражении s^2, то все выражения s, s^3, s^7 и т.д. останутся в прежнем виде и не будут ничем заменены (пример In[8]).

Следует отметить, что в ряде случаев в поздних версиях Mathematica на попытку выполнить выражение вроде $$s^2^=t$$ программа выдаёт сообщение об ошибке, но присваивание всё-таки осуществляет. Так или иначе, уповать на это не стоит, и следует пользоваться тем методом, который однозначно, без дополнительных сообщений, приводит к требуемому результату.

(рис 10.3) Задание глобальных правил преобразования присваиванием верхних значений

При помощи задания верхних значений можно строить простейшие базы данных (Е. М. Воробьёв [1, с. 146]). В примере на рис. 10.4 мы создаём базу данных о галилеевых спутниках Юпитера. Мы задаём информацию о массе спутника как верхнее значение выражения Mass[satname], где satname — название спутника (Io, Callisto, Europa и Ganymede), а также о размерах спутника и дате открытия — верхние значения выражений Dimension[satname] и OpeningDate[satname], соответственно. Теперь узнать информацию о спутнике satname можно, задав выражение ?satname. В примере In[13] на рис. 10.4. мы выводим данные о спутнике Ганимед, введя ?Ganymede.

Подробней о присвоении верхних значений см. книгу Е. М. Воробьёва [1, с. 145–148].

(рис 10.4) Присвоение верхних значений выражений для создания простейших баз данных

Есть в Mathematica и понятие нижних значений, которое тесно связанно с хорошо известными нам по предыдущей лекции пользовательскими функциями.

В примере In[1] на рис. 10.5 зададим функцию DoubSqr, возводящую в квадрат заданное выражение и удваивающую полученный результат. Теперь DoubSqr[expr] для любого выражения expr будет заменяться выражением 2 expr2 (пример In[2]). Это правило преобразования и будет составлять одно из так называемых нижних значений заголовка DoubSqr.

С любым заголовком можно ассоциировать любое количество нижних значений (Е. М. Воробьёв [1, с. 142]). Например, если мы хотим, чтобы при значении expr, равном 0, функция DoubSqr давала значение 1, зададим нижнее значение выражению с заголовком DoubSqr и аргументом 0 — пример In[3] на рис. 10.5.

Вывести на экран нижние значения, ассоциированные с заголовком arbhead, можно, применив к нему функцию DownValues. Е. М. Воробьёв [1, с. 143] отмечает, что если заголовок ассоциирован с несколькими нижними значениями, то Mathematica будет применять правила преобразований в том порядке, в котором они даны в DownValues: более частные правила предшествуют более общим. Именно поэтому в нашем примере выражение DoubSqr[0] при вычислении даст результат 1, а не 0 — пример In[4] на рис. 10.5.

Теперь попробуем изменить порядок присваивания нижних значений. Присвоим сначала некоторому выражению CubSqrt[4] значение 1000, а затем зададим пользовательскую функцию CubSqrt[x_], возводящую выражение в аргументе в степень 3/2 — примеры In[5] и In[6] на рис. 10.5. В примере In[7] при помощи функции DownValues ознакомимся со списком нижних значений выражения CubSqrt: в Out[7] мы найдём значения, заданные как в In[6], так и в In[5].

Если одному и тому же выражению последовательно присваивается несколько нижних значений (пример In[8] на рис. 10.5), то окончательно присвоенным оказывается то, которое присваивалось позже остальных (пример In[11]).

Подробней о присвоении нижних значений см. книгу Е. М. Воробьёва [1, с. 142–144].

(рис 10.5) Задание глобальных правил преобразования присваиванием нижних значений

10.1.2. Локальные правила преобразования

Зачастую преобразование требуется осуществить не во всём тексте программы, а в отдельно взятом выражении или группе выражений. В этом случае прибегают к локальным правилам преобразования. С локальными правилами преобразования мы уже встречались в предыдущих лекциях, в частности, при работе с дифференциальными уравнениями, при выполнении символьных вычислений. В настоящей лекции мы познакомимся с ними как с основой соответствующего стиля программирования.

Локальными вариантами функций немедленного присваивания Set и отложенного присваивания SetDelayed являются функции Rule и RuleDelyed. Их инфиксные формы выглядят как " -> " и " :> ", соответственно. Ещё две инфиксные формы задания этих функций выглядят соответственно как " \to " и " :\to ", и ввести их можно, пользуясь палитрой. Кроме того, в последних версиях Mathematica введённое с клавиатуры выражение -> автоматически преобразовывается в " \to ", а " :> " — в " :\to ". С функцией Rule в инфиксной форме мы уже имели дело, когда в предыдущих лекциях знакомились с опциями функций.

Как мы уже знаем, если в тексте программы мы воспользуемся функцией Set[x,y], то во всех выражениях, содержащих символ x, он будет заменён символом y. Если же в тексте программы мы воспользуемся функций Rule[x,y] (пример In[1] на рис. 10.6), то никаких замен, связанных с символом x, ни в одном выражении не произойдёт (пример In[2]). Для того чтобы всё-таки осуществить замену в некотором выражении, нужно воспользоваться функцией ReplaceAll, указав в качестве её аргументов это самое выражение и необходимую локальную замену. Если, например, в выражении x^2+x+1 мы хотим заменить символ x выражением a+b, то мы задаём соответствующую функцию в следующей форме: ReplaceAll[x^2+x+1,Rule[x,a+b]] (пример In[3]). Функция ReplaceAll также имеет инфиксное представление, которое задаётся как " /. ". Итак, функцию из предыдущего примера можно задать следующим образом: $$x^2+x+1/.x->a+b$$ (пример In[4]).

(рис 10.6) Задание локальных правил преобразования при помощи функции Rule

Выражения, содержащие локальные правила преобразования, также имеют собственный порядок вычислений, описанный П. Веллином и др. в [14, с. 165]. В случае немедленной замены при использовании функции Rule порядок вычислений следующий. Сначала полностью вычисляется выражение, выступающее в качестве первого аргумента функции ReplaceAll (или находящееся слева от инфиксного выражение " /. "). Затем вычисляются выражения в левой и правой частях правил преобразования (второго аргумента функции ReplaceAll или стоящего справа от " /. "). В самом конце выражения в левой части правил, содержащиеся в первом аргументе функции ReplaceAll, заменяются выражениями в правой части правил. Порядок расчёта можно проследить при помощи уже известной нам функции Trace.

В примере In[1] на рис. 10.7 мы задаём некоторое выражение $$(m+n)^2$$, представляем его в полиномиальном виде, и осуществляем замену символов m и n выражениями Sin[2.] и Cos[2.], соответственно. В том же примере мы знакомимся с тем фактом, что к одному и тому же выражению мы можем применять одновременно несколько правил преобразований: в этом случае они должны быть оформлены в виде списка. В примере In[2] мы применяем функцию Trace к выражению в In[1]. По результату, содержащемуся в Out[2], можно поэтапно проследить, что Mathematica делает с исходным выражением на каждом этапе:

  • вычисляет заданное выражение Expand[(m+n)^2] и получает в результате вычисления новое выражение $$m^2+2mn+n^2$$;
  • вычисляет значение выражения Sin[2.], получает число 0.909297;
  • переписывает первое правило преобразования c учётом результатов предыдущего пункта как $$m->0.909297$$;
  • вычисляет значение выражения Cos[2.], получает -0.416147;
  • переписывает второе правило преобразования c учётом результатов предыдущего пункта как $$n->-0.416147$$;
  • переписывает все правила преобразований с учётом вычислений в виде {m->0.909297,n->-0.416147};
  • полностью переписывает выражение с правилами преобразований с учётом всех проведённых вычислений, m^2+2mn+n^2/.{m->0.909297,n->-0.416147};
  • производит замену в соответствии с правилами преобразований, $$0.909297^2+2 0.909297 (-0.416147)+(-0.416147)^2$$;
  • по отдельности вычисляет значения каждого члена выражения, полученного в предыдущем пункте;
  • переписывает выражение, полученное в пункте 8 сего перечня с учётом вычислений в предыдущем пункте, 0.826822 -0.756802 +0.173178, проводит вычисления и получает конечный результат 0.243198 (который, к слову, совпадает с выражением в Out[1] на рис. 10.7).
  • В случае отложенной замены (функция RuleDelayed) вычисление выражений в правой части правил преобразований осуществляется после подстановки, то есть, пункты 2 и 4 представленного выше перечня следуют после пункта 7. Это также легко пронаблюдать при помощи функции Trace — см. пример In[4] на рис. 10.7.

    (рис 10.7) Порядок вычисления выражений, содержащие локальные правила преобразования

    Правила преобразования могут применяться к символам, причём нигде не оговорено, какую роль в тексте программы эти символы должны выполнять. В предыдущих примерах мы применяли замену к символам, являющимся переменными в некотором выражении. Однако преобразуемый символ может являться и заголовком выражения. В примере In[1] на рис. 10.8 мы преобразуем полином в список входящих в него слагаемых, заменяя символ Plus, задающий сумму выражений, символом List, задающим список. Обратный пример преобразования списка в сумму его элементов приведён в книге П. Веллина и др. [14, с. 166].

    В примере 10.7 мы уже познакомились с возможностью применения к выражению одновременно нескольких правил преобразований: для этого правила оформляются в виде списка. Следует учесть, что эффект параллельного применения правил отличается от последовательного, когда каждое новое правило применяется при помощи отдельной функции ReplaceAll. В примере In[2] на рис. 10.8 мы одновременно применили к выражению $$a*x^2+x*a^2$$ правила преобразования $$a->x$$ и $$x->y$$, а в примере In[3] — последовательно. Результаты вычислений Out[2] и Out[3] разительно отличаются друг от друга. Объясняется это достаточно просто: если в первом случае (в примере In[2]) оба правила, и a->x, и x->y, применяются к исходному выражению $$a*x^2+x*a^2$$, то во втором (в примере In[3]) к нему применяется только правило $$a->x$$, а правило $$x->y$$ применяется к результату предыдущей замены, то есть, к уже изменённому выражению.

    Зачастую в процессе вычисления некоторого выражения каждое новое преобразование, подразумевающее замену некоторого символа expr1 символом expr2, приводит к новому выражению, вновь содержащему expr1. Если задачей ставится окончательно избавиться от expr1 в исходном выражении, заменив его выражением expr2, можно прибегнуть к многократному применению правил преобразования. Функция ReplaceRepeated, заданная в виде ReplaceRepeated[initaxpr,rules], будет до тех пор применять правила rules, пока получаемое в результате выражение не перестанет изменяться. Инфиксная форма функции ReplaceRepeated в Mathematica — " //. ". В примере In[4] на рис. 10.8 мы воспользовались многократным преобразованием некоторого выражения, а в примере In[5] для сравнения применили однократное преобразование. Как мы видим, в результате вычислений Out[5] по-прежнему содержится символ q, для которого задавалось правило, а в Out[4] символов, требующих замены не осталось.

    Однако следует быть осторожным при работе с функцией ReplaceRepeated: некоторые правила преобразования могут вызывать принципиальную невозможность точного выполнения функции. Так в примере In[6] на рис. 10.8 мы пытаемся заменить содержащийся в исходном выражении символ t выражением, которое также содержит этот символ, тем самым, ввергая программу в бесконечную рекурсию. В результате мы получаем сообщение о том, что операция преобразования была выполнена 65536 раз и после этого остановлена, а выходная ячейка Out[6] содержит результат применения правила преобразования 65536 раз.

    Подробней о локальных правилах преобразований см. книги Е. М. Воробьёва [1, с. 141, 158–162] и П. Веллина и др. [14, с. 164–167].

    (рис 10.8) Применение локальных правил преобразования

    10.2. Шаблоны

    10.2.1. Использование шаблонов в глобальных правилах преобразования

    В Mathematica, согласно А.Н. Прокопене и А.В. Чичурину [5, с. 89], "шаблоном является выражение, содержащее символ подчёркивания "_"(выражение Blanc[])". С подобными выражениями мы уже встречались в предыдущей лекции, посвящённой функциональному программированию, когда учились задавать пользовательские функции.

    Е. М. Воробьёв [1, с. 148] весьма точно определяет назначение шаблонов: "В принципе шаблоны используются для выделения классов выражений "Математики"".

    Самый широкий класс выражений очерчивает самый простой шаблон, состоящий только из одного символа подчёркивания " _ ". Этому классу соответствуют абсолютно все выражения Mathematica.

    Можно объединить в один класс выражения, обладающие определённым заголовком head: для этого задаётся шаблон вида _head. Для того чтобы задать шаблон для действительных чисел, следует записать _Real, а чтобы выделить в отдельный класс все символьные выражения — задать _Symbol.

    Для того чтобы определить, относится ли то или иное выражение expr к классу данных, задаваемому некоторым шаблоном pat, следует воспользоваться функцией MatchQ[expr,pat]: она возвращает значение True, если выражение expr соответствует шаблону pat, и значение False — если не соответствует.

    В примере In[1] на рис. 10.9 мы проверяем на принадлежность классу данных, задаваемых шаблоном " _ ", ряд выражений различных типов данных. Как мы видим в Out[2], все они соответствуют данному шаблону. В примере In[2] для проверки мы задаём новый шаблон вида _Complex, описывающий комплексные числа, а в In[3]_List для поиска списков.

    Заголовок head не обязательно должен быть стандартным выражением Mathematica. Для иллюстрации этого факта воспользуемся примером, аналогичным приведённому в книге П. Веллина и др. [14, с. 152] — см. пример In[4] на рис. 10.9: в качестве шаблона мы задаём выражение _g, где g — заголовок неопределённой функции, а затем проверяем ряд выражений на соответствие этому шаблону.

    (рис 10.9) Проверка выражений на соответствие заданным шаблонам

    Для иллюстрации следующей особенности задания шаблонов воспользуемся примером, приведённым в работе Е. М. Воробьёва [1, с.149] — см. In[1] на рис. 10.10. Очевидно и для пользователя, и для программы, что выражение x^3 соответствует шаблону _Symbol^_Integer. В математике любое целое число (в нашем примере показатель степени 3) можно представить как сумму двух других целых чисел. Поэтому у пользователя может возникнуть предположение, что приведённое выражение должно соответствовать и шаблону _Symbol^(_Integer+_Integer). Но в этой ситуации Mathematica не согласна с пользователем, поскольку, как справедливо пишет Е. М. Воробьёв [1, с. 149], она "сравнивает внутренние полные формы выражения и шаблона, а не устанавливает их математическую эквивалентность".

    Шаблоны вида " _ " и _h являются анонимными: первый, как мы уже знаем, описывает абсолютно любые выражения, а второй задаёт ограничение по заголовку выражения. Однако для большей конкретизации критериев соответствия шаблону и, соответственно, сужения класса выражений может возникнуть необходимость прибегнуть к именованным шаблонам, которые задаются в виде symb_, где symb — некоторый символ. Проиллюстрируем разницу между шаблонами _Symbol и Symbol_ в примерах In[2] и In[3] на рис. 10.10. Мы воспользовались новой функцией Cases, которая, будучи заданной в виде Cases[{expr1,expr2,…},patts], выбирает из списка выражений {expr1,expr2,…} только те, которые соответствуют шаблонам patts. В обоих примерах (In[2] и In[3]) мы предоставляем для проверки соответствия шаблонам один и тот же список выражений {g^h,g^g,h^h,h^g,f[y]^f[y]}, но получаем (в Out[2] и Out[3], соответственно) совершенно разные результаты.

    В первом примере (In[2]) при отборе играют роль два ключевых критерия.

    Во-первых, отбираются только те выражения, и в основании, и в показателе степени которых содержатся выражения с заголовком Symbol: именно поэтому не функцией Cases игнорируется выражение f[y]^f[y], поскольку оба заголовка есть f.

    Во-вторых, совершенно не имеет значения, совпадают выражения в основании и показателе степени (g^g,h^h) или нет (g^h,h^g): в обоих случаях выражения оказываются соответствующими шаблону.

    Во втором примере Symbol определяет не требуемый для соответствия заголовок, а попросту указывает на присутствие некоторого выражения, поэтому никакого несоответствия в выражении f[y]^f[y] функция Cases не находит. Однако другой критерий задаёт необходимость того, чтобы выражения в основании и показателе степени были одинаковыми, поскольку в обеих частях шаблона используется одно и то же выражение Symbol_. Именно поэтому не проходят проверку на соответствие выражения g^h и h^g, и отбираются в результирующий список выражения g^g и h^h.

    Подробней о шаблонах см. книги Е. М. Воробьёва [1, с. 148–151] и П. Веллина и др. [14, с. 151–153].

    (рис 10.10) Особенности задания анонимных и именованных шаблонов

    Для задания шаблонов могут использоваться выражения, содержащие два и три символа подчёркивания, — " __ " и " ___ ". Их внутренние представления имеют, соответственно, следующий вид: BlankSequence[] и BlankNullSequence[]. Таки шаблоны оказываются необходимыми и эффективными при работе со списками.

    Выражение вида h__, то есть, содержащее двойное подчёркивание, очерчивает класс выражений, состоящих из одного или более выражений с заголовком h, разделённых запятыми.

    Выражение вида h___ (содержащее тройное подчёркивание) очерчивает класс выражений, состоящих из нуля или более выражений с заголовком h, также разделённых запятыми.

    Проиллюстрируем действие шаблонов с двойным и тройным подчёркиванием на примере, аналогичном приведённому в работе П. Веллина и др. [14, с. 153–154]. Пусть мы имеем двухуровневый вложенный список {{a,b},{c},{d,e},{},{f,g,h}}, элементами которого являются списки, содержащие от нуля до трёх элементов. В примере In[1] на рис. 10.11 при помощи функции Cases мы выберем из этого списка элементы, соответствующие шаблону x_, в примере In[2] — шаблону y__, a в примере In[3] — шаблону z___. В первом примере в результирующий список Out[1] попало только одно выражение, представляющее собой список, содержащий один элемент. Во втором примере результирующий список оказался значительно шире: помимо выражения {c}, отобранного и в предыдущем примере, в него также попали списки с двумя и тремя элементами. В последнем примере результирующий список оказался полностью идентичен исходному, поскольку помимо выражений, содержащихся и в Out[2], в него попали и пустые списки {}, проигнорированные в обоих предыдущих примерах.

    Подробней о шаблонах с двумя и тремя подчёркиваниями см. книги Е. М. Воробьёва [1, с. 149–150] и П. Веллина и др. [14, с. 153–156].

    (рис 10.11) Использование шаблонов, содержащих двойные и тройные подчёркивания

    10.2.2. Задание шаблонов с условиями

    В предыдущих разделах мы научились задавать правила преобразований и шаблоны для выделения класса выражений, соответствующих значениям гладких математических функций, таких, как правило преобразования, удваивающее квадрат заданного выражения в примере In[1] на рис. 10.5, и шаблон для функций вида xa в примерах на рис. 10.10. Пусть некоторая функция f(x) переменной x принимает значения f1(x) при x<0, значение 0 при x=0 и значения f2(x) при x>0. Для того чтобы задать правило преобразования для такой функции, используют функцию постановки условий Condition. Задаётся эта функция в виде Condition[rppatt,cond], где rppatt — правая часть правила преобразования при условии cond. Так для нашей предполагаемой функции f(x) при условии x<0 правило устанавливается следующим образом: f[x_]:=Condition[f1[x],x<0]. Функция Condition имеет также инфиксную форму " /; ", и задание правила для функции f(x) будет выглядеть как f[x_]:=f1[x]/;x<0. Безусловно, операции сравнения требуют, чтобы участвующие в них выражения были числами.

    На рис. 10.12 приведено несколько примеров задания правил преобразований с условиями. В In[1] мы отдельно задаём правила преобразования для отрицательных и неотрицательных значениях аргумента. Если аргумент y функции g[y_] примет отрицательное значение (например, -2, как в первом элементе списка In[3]), то будет найден его синус (-Sin[2]), если нулевое или положительное (например, 1) — косинус (Cos[1]). Поскольку для случая, если аргумент y не является числом (k), никаких условий не указано, к выражению никаких правил преобразований применяться не будет, и оно будет переписано в исходном виде с указанным аргументом (g[k]).

    В примере In[4] мы выбираем из некоторого списка выражений только те, показатель степени которых чётный. Для этого мы, во-первых, задаём шаблон для выбора выражений со степенью, _^x_, и во-вторых, задаём условие для отфильтровывания нечётных степеней, EvenQ[x].

    Подробней о шаблонах с условиями см. книги Е. М. Воробьёва [1, с. 152–153] и П. Веллина и др. [14, с. 156–159].

    (рис 10.12) Задание правил преобразования и шаблонов с условиями

    10.2.3. Задание шаблонов-альтернатив

    Если имеется некоторый набор шаблонов, и требуется проверить, соответствует ли то или иное выражение хотя бы одному из них, используются так называемые шаблоны-альтернативы, которые П. Веллин и др. [14, с. 159] определяет как выражения вида patt1|patt2|..., где patt1,patt2,... — независимые шаблоны.

    На рис. 10.13 приведём ряд примеров, аналогичных примерам в работе (П. Веллин и др. [14, с. 160]), которые иллюстрируют возможности применения шаблонов-альтернатив. В примере In[1] мы проверяем, представляет ли собой выражение a^5 символ а, возведённый в целочисленную степень либо символ а, возведённый в вещественную степень. Для полноты иллюстрации в In[2] мы проводим такие же манипуляции с выражением a^5.1. В результате обоих вычислений, как и ожидалось, мы получаем True. В примерах In[3] и In[4] мы проверяем те же выражения на соответствие шаблону "символ a, возведённый в целую или вещественную степень", то есть, задаём альтернативу не для полной формы выражения, а только для показателя степени. В примере In[5] из списка разнотипных данных мы выбираем только те элементы, которые являются целыми или рациональными числами.

    Подробней о шаблонах-альтернативах см. книгу П. Веллина и др. [14, с. 159–161].

    (рис 10.13) Задание и использование шаблонов-альтернатив

    10.2.4. Использование шаблонов в локальных правилах преобразования

    Использование шаблонов в локальных правилах преобразований подробно комметирует Е. М. Воробьёв в своей книге [1, с. 158–162]. Как мы помним из пункта 10.1.2, локальные правила преобразования задаются выражениями вида exprl->expr2 и exprl:>expr2. В настоящем пункте мы научимся задавать локальные правила преобразования, содержащие в выражении expr1 шаблоны. Для этого воспользуемся примером, аналогичным, приведённому в книге Е. М. Воробьёва [1, с. 159–160]. Применим к представляющему собой список выражению {m,n} три разных набора правил подстановки. В примере In[1] на рис. 10.14 зададим правила {m->a,n->b}. Результат преобразований Out[1] достаточно очевиден: m заменено на a, n — на b. В примере In[2] добавим к имеющимся ещё одно правило {m,n}->c. Результирующее выражение Out[2] отличается от Out[1], поскольку последнее правило замены, как оказалось, гораздо больше соответствует преобразуемому выражению.

    Теперь попробуем осуществить ту же замену при помощи шаблонов. Для этого в примере In[3] на рис. 10.14 зададим правило замены в виде {x_,y_}->c.

    Как мы выяснили в примерах In[1] и In[2] на рис. 10.14, в случае, если к некоторому выражению применено несколько правил преобразования, не содержащих шаблоны, то в первую очередь выполняется то, которое больше соответствует изменяемому выражению. Определим, какое из правил будет выполняться, если они содержат шаблоны. В примере In[4] применим к тому же выражению {m,n} набор правил преобразований {{x_,x_}->c,{_,_}->d}. Хотя исходное выражение соответствует обоим шаблонам, преобразование было выполнено по правилу {x_,x_}->c. В примере In[5] поменяем местами правила преобразований в наборе, т.е., зададим {{_,_}->d,{x_,x_}->c}. Результат в Out[4] показывает, что в данном случае была осуществлена замена по другому правилу, {_,_}->d. Следовательно, если изменяемое выражение соответствует нескольким шаблонам в правилах преобразований, выполняется то правило, которое указано раньше остальных.

    (рис 10.14) Использование шаблонов в локальных правилах преобразований

    Специфическим образом осуществляется вычисление функции многократного применения локальных правил преобразований ReplaceRepeated с шаблонами. Эта специфика доступно пояснена в книге Е. М. Воробьёва [1, с. 160]: "…ее [функции ReplaceRepeated] вычисление сводится к повторному вычислению функции ReplaceAll до тех пор, пока ни одно из подвыражений преобразуемого выражения не удается преобразовать в соответствии с хотя бы одним шаблоном списка. При этом порядок применения шаблонов следующий. Первый шаблон списка используется, пока в преобразуемом выражении находится хотя бы одно подвыражение, ему соответствующее. Затем применяется второй шаблон списка и т.д. Ни в коем случае не следует думать, что каждый раз применяется более чем один шаблон списка".

    На рис. 10.15. приведён пример также из книги Е. М. Воробьёва [1, с. 160], иллюстрирующий действие функции ReplaceRepeated. Первый шаблон списка был применён дважды: в результате исходное выражение было сведено к одноэлементному списку {а}. Затем к полученному на предыдущем этапе выражению был применён третий шаблон. Второй шаблон не использовался ни разу, хотя на одном из этапов преобразования и получалось соответствующее ему выражение. После применения третьего шаблона результирующее выражение a оказывается несоответствующим ни одному указанному шаблону, и вычисления прекращаются.

    (рис 10.15) Использование шаблонов при использовании функции многократного применения правил преобразований ReplaceRepeated

    Ключевые термины

    Верхнее значение выражения — это правило преобразования, ассоциированное с находящимся на первом уровне выражения элементом этого выражения.

    Глобальным называется правило преобразования, которое осуществляет заданное преобразование во всём тексте программы.

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

    Нижнее значение выражения — это правило преобразования, ассоциированное с заголовком выражения независимо от его элементов на нижних уровнях.

    Шаблоном является выражение, содержащее символ подчёркивания (выражение Blanc[]).

    Краткие итоги

    В данной лекции мы познакомились с принципами программирования на языке Mathematica в стиле, основанном на использовании правил преобразований. В частности мы с новой позиции познакомились с операциями присваивания и отложенного присваивания, выступающими в роли глобальных правил преобразований. Мы научились осуществлять присваивание абсолютно любым выражениям: обходить запрет на присваивание и задавать верхние и нижние значения выражений. Мы познакомились с принципами задания локальных правил преобразований и их использования в вычислениях. Мы научились избирательно обрабатывать выражения в зависимости от их типа и структуры при помощи шаблонов. Также мы научились применять шаблоны при задании глобальных и локальных правил преобразований.

    Вопросы

  • Какие преобразования называются в Mathematica глобальными? Каким образом задаются глобальные правила преобразований?
  • Для каких целей выражения снабжаются атрибутом Protected? Каким образом атрибут Protected можно убрать из списка атрибутов выражения? Добавить в список?
  • Что такое верхнее значение выражения? Каким образом осуществляется присвоение выражениям верхних значений?
  • Что такое нижнее значение выражения? Каким образом осуществляется присвоение выражениям нижних значений?
  • Какие преобразования называются в Mathematica локальными? Каким образом задаются локальные правила преобразований?
  • Какие выражения в Mathematica называются шаблонами?
  • Чем отличаются друг от друга шаблоны _h и h_?
  • Какие классы выражений выделяют шаблоны с двумя и тремя символами подчёркивания? При работе с каким классом данных их целесообразно использовать?
  • В каких случаях используются шаблоны с условиями? Каким образом они задаются?
  • В каких случаях используются шаблоны-альтернативы? Каким образом они задаются?
  • Упражнения

  • Опишите процесс вычисления следующих наборов выражений (в скобках для проверки указан результат каждого вычисления).
  • x=a;

    y=b;

    x+10/.x->6

    (результат: 16)

  • a=5;

    x:=a;

    y=b;

    a=10;

    x+10/.x->y

    (результат: 20)

  • a=5;

    x=a;

    y=b;

    a=10;

    x+10/.x->y

    (результат: 15)

  • a=c;

    x=a;

    y=b;

    a=10;

    x+10/.x->y

    (результат: 10+b)

  • Set[k,10];

    SetDelayed[l,u];

    ReplaceAll[l^2-k,Rule[k,l]]

    (результат: -10+u^2)

  • Set[n,5];

    SetDelayed[k,n];

    SetDelayed[l,u];

    Set[n,10];

    ReplaceAll[l^2-k,Rule[k,l]]

    (результат: -10+u^2)

  • SetDelayed[n,5];

    Set[k,n];

    Set[l,u];

    Set[n,10];

    ReplaceAll[l^2-k,Rule[k,l]]

    (результат: -5+u^2)

  • SetDelayed[n,v];

    Set[k,n];

    Set[l,u];

    ReplaceAll[l^2-k,Rule[k,l^2]]

    (результат: 0)

  • SetDelayed[n,v];

    Set[k,n];

    SetDelayed[l,u];

    ReplaceAll[l^2-k,Rule[l,k]]

    (результат: -v+v^2)

  • Присвойте выражениям, записанным слева, значения, указанные справа. Для выполнения задания используйте присвоение верхних значений и управление атрибутом Protected.

    k^l 3

    m^2 n^3

    x+y z

    x+y^2 z^2

    Cos[f] g+h

    Cos[f]+g h

    u^Sqrt[v] w

    u^Sqrt[3] w

    Sqrt[3]^u v

  • При помощи задания нижних значений создайте простейшую базу данных, содержащую информацию о сотрудниках вашего отдела/ студентах вашей академической группы/ членах вашей семьи. Занесите в базу следующие сведения: фамилия, имя, отчество, пол, день, месяц и год рождения.
  • Задайте пользовательскую функцию, которая преобразует строку, содержащую только буквы латинского алфавита, в список, элементами которого являются номера этих букв в алфавите. Для выполнения задания используйте функцию Characters, с которой мы познакомились в лекции 3 сего курса, и локальные правила преобразования.
  • Задайте пользовательскую функцию, дублирующую действие встроенной функции Abs. Используйте при задании шаблоны с условиями.
  • Найдите как можно больше шаблонов, которым соответствуют заданные ниже выражения. Проверьте соответствие при помощи функций MatchQ и Cases.

    a^b+2*c

    a^2+b^2

    a^b+b^a

    1+2*I

    {a,b,c}

    {a,{},b,{},c}

    x[t]^y

    x[t]*y[t]

    a^(2*a+3*b)

  • Страницы:

    Цель лекции: познакомиться с принципами реализации стиля программирования, основанного на правилах преобразований, в языке программирования Mathematica

    10.0. Введение

    Как справедливо отмечает Е. М. Воробьёв [1, с. 140], понятие преобразования является одним из ключевых в математике. Большинство математических операций, математических объектов, так или иначе, связано с преобразованиями. Так таблицу умножения можно рассматривать как совокупность правил преобразований: согласно им мы с полным правом, не боясь условий и ограничений, можем заменить одно выражение, скажем, 3x3, другим — 9. Математические тождества также представляют собой правила преобразования: например, тождество $$(a+b)(a-b)=a^2-b^2$$ позволяет в математических расчётах заменить его правую часть левой или наоборот.

    Операции математического анализа также не являются исключением. Основной задачей математического анализа является приведение выражений, содержащих суммы, интегралы, производные и т.д., к виду, в котором мы можем заменить их другими выражениями согласно справочным данным. Например, в процессе вычисления мы можем неопределённый интеграл от выражения $$cos^2(x)$$ по $$dx$$ заменить выражением $$(x+sin(x) cos(x))/2+const$$. Таким образом, объекты математического анализа также подчиняются правилам преобразования.

    Помимо традиционных математических правил преобразования Mathematica имеет широкий набор средств для создания собственных правил. Именно на них и основывается рассматриваемый в настоящей лекции стиль программирования.

    Программирование, основанное на правилах преобразования (rule-based programming), характеризуется преобразованием объектов данных различных типов (М. А. Марин и др. [10]). Преобразования есть суть вычисления; они описываются правилами замены одних объектов другими согласно некоторому шаблону. Программирование, основанное на правилах преобразования, является наиболее естественным для высокоорганизованного языка программирования Mathematica. Для ознакомления с данным стилем программирования воспользуемся логикой изложения, применённой в работе Е. М. Воробьёва [1].

    10.1. Правила преобразования

    10.1.1. Глобальные правила преобразования

    Е. М. Воробьёв [1, с. 141] начинает знакомство читателей с правилами преобразований с уже известного нам простейшего правила — присвоения некоторого значения a символу x. С инфиксной формой немедленного присваивания мы познакомились в лекции 2 настоящего курса и знаем, что оно осуществляется при помощи знака " = ". Таким образом, выражение x=a означает, что во всех выражениях в тексте программы, содержащих x, его следует заменить выражением a. Поскольку замена осуществляется во всех выражениях программы, то правило преобразования, задаваемое немедленным присваиванием, является глобальным. Внутренней формой операции немедленного присваивания является функция Set[expr1,expr2]: она заменяет выражение expr1 выражением expr2. Е. М. Воробьёв [1, с. 141] так описывает процесс присваивания: "Выражение Set[expr1,expr2] вычисляется следующим образом. Аргумент expr1 вовсе не вычисляется, выражение expr2 вычисляется, и это вычисленное значение присваивается выражению expr1". Он также отмечает, что такой порядок выполнения функции не случаен и имеет строгое обоснование. Рассмотрим это утверждение на примере. Пусть мы задали выражение y=10, то есть, символу y присвоили значение 10. Затем нам понадобилось присвоить символу y новое значение, например, 5, для чего мы задали функцию Set[y,5]. Если бы при выполнении этой функции первый аргумент (y в нашем случае) вычислялся, то Mathematica бы решила, что мы хотим присвоить значение 5 числу 10, что граничит с разумным. Подобного парадокса и помогает избежать описанный алгоритм вычисления функции Set.

    Примеры задания и использования глобального правила преобразования при помощи функции немедленного присваивания Set в инфиксной (In[1] и In[2]) и внутренней (In[3] и In[4]) форме см. на рис. 10.1.

    (рис 10.1) Задание глобального правила преобразования при помощи функции Set

    В примерах на рис. 10.1 мы присваивали выражения некоторым символам, хотя, в принципе в качестве выражения expr1, которому присваивается значение expr2, может выступать любое выражение. В примере In[1] на рис. 10.2 мы присвоили некоторой неопределённой функции f[x] значение 5, а в примере In[2] вычислили квадрат выражения f[x]: результат вычисления в Out[2] непосредственно связан с ранее присвоенным выражению численным значением 5.

    Однако если мы попытаемся присвоить значение выражению, содержащему в теле некоторую встроенную функцию, например, Plus (пример In[3] на рис. 10.2), то нас постигнет неудача: значение не будет присвоено и Mathematica выдаст предупреждающее сообщение о том, что функция Plus обладает атрибутом Protected. Этот атрибут защищает выражение с данным заголовком от присваивания значений. И всё же даже выражениям с защищёнными заголовками значения могут быть присвоены. Для этого следует убрать из списка принадлежащих функции атрибутов атрибут Protected, применив к ней функцию Unprotect (пример In[4]). После этой процедуры никаких препятствий к присвоению значений не остаётся (примеры In[5] и In[6]). Похожую процедуру для функции Power описывает Е. М. Воробьёв [1, с. 144–145].

    Однако Mathematica приписывает функциям атрибут Protected не из желания усложнить пользователю жизнь. Дело в том, что в процессе вычислений программе приходится иметь дело с большим числом правил преобразований. Поскольку большинство встроенных функций, таких, как Plus, Times, Power и др., используются при вычислении достаточно часто, то любое дополнительное правило преобразования, ассоциированное с ними, оказывает влияние на скорость вычислений и может значительно замедлить работу программы. Именно поэтому следует снова защитить такие функции от присваивания, если атрибут Protected однажды был убран из списка их атрибутов. Делается это, как не сложно предположить, при помощи функции Protect. Так в примере In[7] мы снова присваиваем функции Plus атрибут Protected, а в In[8] убеждаемся в том, что он присвоен, выведя на экран все атрибуты функции Plus.

    Подробней об атрибуте Protected см. книгу Е. М. Воробьёва [1, с. 142, 144–145].

    (рис 10.2) Присвоение значения выражению, защищённому атрибутом Protected

    Существует ещё один способ присваивания значений защищённым выражениям — применение так называемых верхних значений. Этот способ позволяют ассоциировать правила преобразований с элементами, находящимися на первом уровне выражений: при этом совершенно не важно, является ли заголовок защищённым. Присваивание осуществляется функциями UpSet и UpSetDelay, инфиксные формы которых выглядят как " ^= " и " ^:= ", соответственно.

    Для иллюстрации возможностей использования верхних значений приведём пример, аналогичный примеру в книге Е. М. Воробьёва [1, с. 145]. В In[1] на рис. 10.3 мы заменяем выражение p^q символом r. Теперь символ r ассоциирован с выражениями p и q и является их верхним значением, в чём мы убеждаемся в примерах In[2] и In[3], запрашивая сведения об этих выражениях. В примере In[4] на рис. 10.3 мы вводим некоторое выражение, содержащее p^q, и в результате вычислений Out[4] видим, что p^q действительно было заменено символом r.

    В примере In[5] на рис. 10.3 мы попробуем присвоить верхнее значение t выражению s^2. К нашему удивлению, попытка совершить подобное действие терпит фиаско: Mathematica выдаёт сообщение о том, что защищённым является заголовок Integer, который, как мы знаем, отвечает за целочисленный тип данных. Заставить Mathematica осуществить присваивание в этом случае невозможно, поскольку правило преобразования можно ассоциировать с символами, и нельзя — с числами и строками. Однако и из этой, казалось бы, тупиковой ситуации есть выход. Можно присвоить верхнее значение выражению s^2, ассоциировав новое правило только с символом s в этом выражении. Делается это при помощи функции TagSet, инфиксная форма которой " /: " (примеры In[6] и In[7]). Поскольку в наших примерах s ассоциировано с t только в выражении s^2, то все выражения s, s^3, s^7 и т.д. останутся в прежнем виде и не будут ничем заменены (пример In[8]).

    Следует отметить, что в ряде случаев в поздних версиях Mathematica на попытку выполнить выражение вроде $$s^2^=t$$ программа выдаёт сообщение об ошибке, но присваивание всё-таки осуществляет. Так или иначе, уповать на это не стоит, и следует пользоваться тем методом, который однозначно, без дополнительных сообщений, приводит к требуемому результату.

    (рис 10.3) Задание глобальных правил преобразования присваиванием верхних значений

    При помощи задания верхних значений можно строить простейшие базы данных (Е. М. Воробьёв [1, с. 146]). В примере на рис. 10.4 мы создаём базу данных о галилеевых спутниках Юпитера. Мы задаём информацию о массе спутника как верхнее значение выражения Mass[satname], где satname — название спутника (Io, Callisto, Europa и Ganymede), а также о размерах спутника и дате открытия — верхние значения выражений Dimension[satname] и OpeningDate[satname], соответственно. Теперь узнать информацию о спутнике satname можно, задав выражение ?satname. В примере In[13] на рис. 10.4. мы выводим данные о спутнике Ганимед, введя ?Ganymede.

    Подробней о присвоении верхних значений см. книгу Е. М. Воробьёва [1, с. 145–148].

    (рис 10.4) Присвоение верхних значений выражений для создания простейших баз данных

    Есть в Mathematica и понятие нижних значений, которое тесно связанно с хорошо известными нам по предыдущей лекции пользовательскими функциями.

    В примере In[1] на рис. 10.5 зададим функцию DoubSqr, возводящую в квадрат заданное выражение и удваивающую полученный результат. Теперь DoubSqr[expr] для любого выражения expr будет заменяться выражением 2 expr2 (пример In[2]). Это правило преобразования и будет составлять одно из так называемых нижних значений заголовка DoubSqr.

    С любым заголовком можно ассоциировать любое количество нижних значений (Е. М. Воробьёв [1, с. 142]). Например, если мы хотим, чтобы при значении expr, равном 0, функция DoubSqr давала значение 1, зададим нижнее значение выражению с заголовком DoubSqr и аргументом 0 — пример In[3] на рис. 10.5.

    Вывести на экран нижние значения, ассоциированные с заголовком arbhead, можно, применив к нему функцию DownValues. Е. М. Воробьёв [1, с. 143] отмечает, что если заголовок ассоциирован с несколькими нижними значениями, то Mathematica будет применять правила преобразований в том порядке, в котором они даны в DownValues: более частные правила предшествуют более общим. Именно поэтому в нашем примере выражение DoubSqr[0] при вычислении даст результат 1, а не 0 — пример In[4] на рис. 10.5.

    Теперь попробуем изменить порядок присваивания нижних значений. Присвоим сначала некоторому выражению CubSqrt[4] значение 1000, а затем зададим пользовательскую функцию CubSqrt[x_], возводящую выражение в аргументе в степень 3/2 — примеры In[5] и In[6] на рис. 10.5. В примере In[7] при помощи функции DownValues ознакомимся со списком нижних значений выражения CubSqrt: в Out[7] мы найдём значения, заданные как в In[6], так и в In[5].

    Если одному и тому же выражению последовательно присваивается несколько нижних значений (пример In[8] на рис. 10.5), то окончательно присвоенным оказывается то, которое присваивалось позже остальных (пример In[11]).

    Подробней о присвоении нижних значений см. книгу Е. М. Воробьёва [1, с. 142–144].

    (рис 10.5) Задание глобальных правил преобразования присваиванием нижних значений

    10.1.2. Локальные правила преобразования

    Зачастую преобразование требуется осуществить не во всём тексте программы, а в отдельно взятом выражении или группе выражений. В этом случае прибегают к локальным правилам преобразования. С локальными правилами преобразования мы уже встречались в предыдущих лекциях, в частности, при работе с дифференциальными уравнениями, при выполнении символьных вычислений. В настоящей лекции мы познакомимся с ними как с основой соответствующего стиля программирования.

    Локальными вариантами функций немедленного присваивания Set и отложенного присваивания SetDelayed являются функции Rule и RuleDelyed. Их инфиксные формы выглядят как " -> " и " :> ", соответственно. Ещё две инфиксные формы задания этих функций выглядят соответственно как " \to " и " :\to ", и ввести их можно, пользуясь палитрой. Кроме того, в последних версиях Mathematica введённое с клавиатуры выражение -> автоматически преобразовывается в " \to ", а " :> " — в " :\to ". С функцией Rule в инфиксной форме мы уже имели дело, когда в предыдущих лекциях знакомились с опциями функций.

    Как мы уже знаем, если в тексте программы мы воспользуемся функцией Set[x,y], то во всех выражениях, содержащих символ x, он будет заменён символом y. Если же в тексте программы мы воспользуемся функций Rule[x,y] (пример In[1] на рис. 10.6), то никаких замен, связанных с символом x, ни в одном выражении не произойдёт (пример In[2]). Для того чтобы всё-таки осуществить замену в некотором выражении, нужно воспользоваться функцией ReplaceAll, указав в качестве её аргументов это самое выражение и необходимую локальную замену. Если, например, в выражении x^2+x+1 мы хотим заменить символ x выражением a+b, то мы задаём соответствующую функцию в следующей форме: ReplaceAll[x^2+x+1,Rule[x,a+b]] (пример In[3]). Функция ReplaceAll также имеет инфиксное представление, которое задаётся как " /. ". Итак, функцию из предыдущего примера можно задать следующим образом: $$x^2+x+1/.x->a+b$$ (пример In[4]).

    (рис 10.6) Задание локальных правил преобразования при помощи функции Rule

    Выражения, содержащие локальные правила преобразования, также имеют собственный порядок вычислений, описанный П. Веллином и др. в [14, с. 165]. В случае немедленной замены при использовании функции Rule порядок вычислений следующий. Сначала полностью вычисляется выражение, выступающее в качестве первого аргумента функции ReplaceAll (или находящееся слева от инфиксного выражение " /. "). Затем вычисляются выражения в левой и правой частях правил преобразования (второго аргумента функции ReplaceAll или стоящего справа от " /. "). В самом конце выражения в левой части правил, содержащиеся в первом аргументе функции ReplaceAll, заменяются выражениями в правой части правил. Порядок расчёта можно проследить при помощи уже известной нам функции Trace.

    В примере In[1] на рис. 10.7 мы задаём некоторое выражение $$(m+n)^2$$, представляем его в полиномиальном виде, и осуществляем замену символов m и n выражениями Sin[2.] и Cos[2.], соответственно. В том же примере мы знакомимся с тем фактом, что к одному и тому же выражению мы можем применять одновременно несколько правил преобразований: в этом случае они должны быть оформлены в виде списка. В примере In[2] мы применяем функцию Trace к выражению в In[1]. По результату, содержащемуся в Out[2], можно поэтапно проследить, что Mathematica делает с исходным выражением на каждом этапе:

  • вычисляет заданное выражение Expand[(m+n)^2] и получает в результате вычисления новое выражение $$m^2+2mn+n^2$$;
  • вычисляет значение выражения Sin[2.], получает число 0.909297;
  • переписывает первое правило преобразования c учётом результатов предыдущего пункта как $$m->0.909297$$;
  • вычисляет значение выражения Cos[2.], получает -0.416147;
  • переписывает второе правило преобразования c учётом результатов предыдущего пункта как $$n->-0.416147$$;
  • переписывает все правила преобразований с учётом вычислений в виде {m->0.909297,n->-0.416147};
  • полностью переписывает выражение с правилами преобразований с учётом всех проведённых вычислений, m^2+2mn+n^2/.{m->0.909297,n->-0.416147};
  • производит замену в соответствии с правилами преобразований, $$0.909297^2+2 0.909297 (-0.416147)+(-0.416147)^2$$;
  • по отдельности вычисляет значения каждого члена выражения, полученного в предыдущем пункте;
  • переписывает выражение, полученное в пункте 8 сего перечня с учётом вычислений в предыдущем пункте, 0.826822 -0.756802 +0.173178, проводит вычисления и получает конечный результат 0.243198 (который, к слову, совпадает с выражением в Out[1] на рис. 10.7).
  • В случае отложенной замены (функция RuleDelayed) вычисление выражений в правой части правил преобразований осуществляется после подстановки, то есть, пункты 2 и 4 представленного выше перечня следуют после пункта 7. Это также легко пронаблюдать при помощи функции Trace — см. пример In[4] на рис. 10.7.

    (рис 10.7) Порядок вычисления выражений, содержащие локальные правила преобразования

    Правила преобразования могут применяться к символам, причём нигде не оговорено, какую роль в тексте программы эти символы должны выполнять. В предыдущих примерах мы применяли замену к символам, являющимся переменными в некотором выражении. Однако преобразуемый символ может являться и заголовком выражения. В примере In[1] на рис. 10.8 мы преобразуем полином в список входящих в него слагаемых, заменяя символ Plus, задающий сумму выражений, символом List, задающим список. Обратный пример преобразования списка в сумму его элементов приведён в книге П. Веллина и др. [14, с. 166].

    В примере 10.7 мы уже познакомились с возможностью применения к выражению одновременно нескольких правил преобразований: для этого правила оформляются в виде списка. Следует учесть, что эффект параллельного применения правил отличается от последовательного, когда каждое новое правило применяется при помощи отдельной функции ReplaceAll. В примере In[2] на рис. 10.8 мы одновременно применили к выражению $$a*x^2+x*a^2$$ правила преобразования $$a->x$$ и $$x->y$$, а в примере In[3] — последовательно. Результаты вычислений Out[2] и Out[3] разительно отличаются друг от друга. Объясняется это достаточно просто: если в первом случае (в примере In[2]) оба правила, и a->x, и x->y, применяются к исходному выражению $$a*x^2+x*a^2$$, то во втором (в примере In[3]) к нему применяется только правило $$a->x$$, а правило $$x->y$$ применяется к результату предыдущей замены, то есть, к уже изменённому выражению.

    Зачастую в процессе вычисления некоторого выражения каждое новое преобразование, подразумевающее замену некоторого символа expr1 символом expr2, приводит к новому выражению, вновь содержащему expr1. Если задачей ставится окончательно избавиться от expr1 в исходном выражении, заменив его выражением expr2, можно прибегнуть к многократному применению правил преобразования. Функция ReplaceRepeated, заданная в виде ReplaceRepeated[initaxpr,rules], будет до тех пор применять правила rules, пока получаемое в результате выражение не перестанет изменяться. Инфиксная форма функции ReplaceRepeated в Mathematica — " //. ". В примере In[4] на рис. 10.8 мы воспользовались многократным преобразованием некоторого выражения, а в примере In[5] для сравнения применили однократное преобразование. Как мы видим, в результате вычислений Out[5] по-прежнему содержится символ q, для которого задавалось правило, а в Out[4] символов, требующих замены не осталось.

    Однако следует быть осторожным при работе с функцией ReplaceRepeated: некоторые правила преобразования могут вызывать принципиальную невозможность точного выполнения функции. Так в примере In[6] на рис. 10.8 мы пытаемся заменить содержащийся в исходном выражении символ t выражением, которое также содержит этот символ, тем самым, ввергая программу в бесконечную рекурсию. В результате мы получаем сообщение о том, что операция преобразования была выполнена 65536 раз и после этого остановлена, а выходная ячейка Out[6] содержит результат применения правила преобразования 65536 раз.

    Подробней о локальных правилах преобразований см. книги Е. М. Воробьёва [1, с. 141, 158–162] и П. Веллина и др. [14, с. 164–167].

    (рис 10.8) Применение локальных правил преобразования

    10.2. Шаблоны

    10.2.1. Использование шаблонов в глобальных правилах преобразования

    В Mathematica, согласно А.Н. Прокопене и А.В. Чичурину [5, с. 89], "шаблоном является выражение, содержащее символ подчёркивания "_"(выражение Blanc[])". С подобными выражениями мы уже встречались в предыдущей лекции, посвящённой функциональному программированию, когда учились задавать пользовательские функции.

    Е. М. Воробьёв [1, с. 148] весьма точно определяет назначение шаблонов: "В принципе шаблоны используются для выделения классов выражений "Математики"".

    Самый широкий класс выражений очерчивает самый простой шаблон, состоящий только из одного символа подчёркивания " _ ". Этому классу соответствуют абсолютно все выражения Mathematica.

    Можно объединить в один класс выражения, обладающие определённым заголовком head: для этого задаётся шаблон вида _head. Для того чтобы задать шаблон для действительных чисел, следует записать _Real, а чтобы выделить в отдельный класс все символьные выражения — задать _Symbol.

    Для того чтобы определить, относится ли то или иное выражение expr к классу данных, задаваемому некоторым шаблоном pat, следует воспользоваться функцией MatchQ[expr,pat]: она возвращает значение True, если выражение expr соответствует шаблону pat, и значение False — если не соответствует.

    В примере In[1] на рис. 10.9 мы проверяем на принадлежность классу данных, задаваемых шаблоном " _ ", ряд выражений различных типов данных. Как мы видим в Out[2], все они соответствуют данному шаблону. В примере In[2] для проверки мы задаём новый шаблон вида _Complex, описывающий комплексные числа, а в In[3]_List для поиска списков.

    Заголовок head не обязательно должен быть стандартным выражением Mathematica. Для иллюстрации этого факта воспользуемся примером, аналогичным приведённому в книге П. Веллина и др. [14, с. 152] — см. пример In[4] на рис. 10.9: в качестве шаблона мы задаём выражение _g, где g — заголовок неопределённой функции, а затем проверяем ряд выражений на соответствие этому шаблону.

    (рис 10.9) Проверка выражений на соответствие заданным шаблонам

    Для иллюстрации следующей особенности задания шаблонов воспользуемся примером, приведённым в работе Е. М. Воробьёва [1, с.149] — см. In[1] на рис. 10.10. Очевидно и для пользователя, и для программы, что выражение x^3 соответствует шаблону _Symbol^_Integer. В математике любое целое число (в нашем примере показатель степени 3) можно представить как сумму двух других целых чисел. Поэтому у пользователя может возникнуть предположение, что приведённое выражение должно соответствовать и шаблону _Symbol^(_Integer+_Integer). Но в этой ситуации Mathematica не согласна с пользователем, поскольку, как справедливо пишет Е. М. Воробьёв [1, с. 149], она "сравнивает внутренние полные формы выражения и шаблона, а не устанавливает их математическую эквивалентность".

    Шаблоны вида " _ " и _h являются анонимными: первый, как мы уже знаем, описывает абсолютно любые выражения, а второй задаёт ограничение по заголовку выражения. Однако для большей конкретизации критериев соответствия шаблону и, соответственно, сужения класса выражений может возникнуть необходимость прибегнуть к именованным шаблонам, которые задаются в виде symb_, где symb — некоторый символ. Проиллюстрируем разницу между шаблонами _Symbol и Symbol_ в примерах In[2] и In[3] на рис. 10.10. Мы воспользовались новой функцией Cases, которая, будучи заданной в виде Cases[{expr1,expr2,…},patts], выбирает из списка выражений {expr1,expr2,…} только те, которые соответствуют шаблонам patts. В обоих примерах (In[2] и In[3]) мы предоставляем для проверки соответствия шаблонам один и тот же список выражений {g^h,g^g,h^h,h^g,f[y]^f[y]}, но получаем (в Out[2] и Out[3], соответственно) совершенно разные результаты.

    В первом примере (In[2]) при отборе играют роль два ключевых критерия.

    Во-первых, отбираются только те выражения, и в основании, и в показателе степени которых содержатся выражения с заголовком Symbol: именно поэтому не функцией Cases игнорируется выражение f[y]^f[y], поскольку оба заголовка есть f.

    Во-вторых, совершенно не имеет значения, совпадают выражения в основании и показателе степени (g^g,h^h) или нет (g^h,h^g): в обоих случаях выражения оказываются соответствующими шаблону.

    Во втором примере Symbol определяет не требуемый для соответствия заголовок, а попросту указывает на присутствие некоторого выражения, поэтому никакого несоответствия в выражении f[y]^f[y] функция Cases не находит. Однако другой критерий задаёт необходимость того, чтобы выражения в основании и показателе степени были одинаковыми, поскольку в обеих частях шаблона используется одно и то же выражение Symbol_. Именно поэтому не проходят проверку на соответствие выражения g^h и h^g, и отбираются в результирующий список выражения g^g и h^h.

    Подробней о шаблонах см. книги Е. М. Воробьёва [1, с. 148–151] и П. Веллина и др. [14, с. 151–153].

    (рис 10.10) Особенности задания анонимных и именованных шаблонов

    Для задания шаблонов могут использоваться выражения, содержащие два и три символа подчёркивания, — " __ " и " ___ ". Их внутренние представления имеют, соответственно, следующий вид: BlankSequence[] и BlankNullSequence[]. Таки шаблоны оказываются необходимыми и эффективными при работе со списками.

    Выражение вида h__, то есть, содержащее двойное подчёркивание, очерчивает класс выражений, состоящих из одного или более выражений с заголовком h, разделённых запятыми.

    Выражение вида h___ (содержащее тройное подчёркивание) очерчивает класс выражений, состоящих из нуля или более выражений с заголовком h, также разделённых запятыми.

    Проиллюстрируем действие шаблонов с двойным и тройным подчёркиванием на примере, аналогичном приведённому в работе П. Веллина и др. [14, с. 153–154]. Пусть мы имеем двухуровневый вложенный список {{a,b},{c},{d,e},{},{f,g,h}}, элементами которого являются списки, содержащие от нуля до трёх элементов. В примере In[1] на рис. 10.11 при помощи функции Cases мы выберем из этого списка элементы, соответствующие шаблону x_, в примере In[2] — шаблону y__, a в примере In[3] — шаблону z___. В первом примере в результирующий список Out[1] попало только одно выражение, представляющее собой список, содержащий один элемент. Во втором примере результирующий список оказался значительно шире: помимо выражения {c}, отобранного и в предыдущем примере, в него также попали списки с двумя и тремя элементами. В последнем примере результирующий список оказался полностью идентичен исходному, поскольку помимо выражений, содержащихся и в Out[2], в него попали и пустые списки {}, проигнорированные в обоих предыдущих примерах.

    Подробней о шаблонах с двумя и тремя подчёркиваниями см. книги Е. М. Воробьёва [1, с. 149–150] и П. Веллина и др. [14, с. 153–156].

    (рис 10.11) Использование шаблонов, содержащих двойные и тройные подчёркивания

    10.2.2. Задание шаблонов с условиями

    В предыдущих разделах мы научились задавать правила преобразований и шаблоны для выделения класса выражений, соответствующих значениям гладких математических функций, таких, как правило преобразования, удваивающее квадрат заданного выражения в примере In[1] на рис. 10.5, и шаблон для функций вида xa в примерах на рис. 10.10. Пусть некоторая функция f(x) переменной x принимает значения f1(x) при x<0, значение 0 при x=0 и значения f2(x) при x>0. Для того чтобы задать правило преобразования для такой функции, используют функцию постановки условий Condition. Задаётся эта функция в виде Condition[rppatt,cond], где rppatt — правая часть правила преобразования при условии cond. Так для нашей предполагаемой функции f(x) при условии x<0 правило устанавливается следующим образом: f[x_]:=Condition[f1[x],x<0]. Функция Condition имеет также инфиксную форму " /; ", и задание правила для функции f(x) будет выглядеть как f[x_]:=f1[x]/;x<0. Безусловно, операции сравнения требуют, чтобы участвующие в них выражения были числами.

    На рис. 10.12 приведено несколько примеров задания правил преобразований с условиями. В In[1] мы отдельно задаём правила преобразования для отрицательных и неотрицательных значениях аргумента. Если аргумент y функции g[y_] примет отрицательное значение (например, -2, как в первом элементе списка In[3]), то будет найден его синус (-Sin[2]), если нулевое или положительное (например, 1) — косинус (Cos[1]). Поскольку для случая, если аргумент y не является числом (k), никаких условий не указано, к выражению никаких правил преобразований применяться не будет, и оно будет переписано в исходном виде с указанным аргументом (g[k]).

    В примере In[4] мы выбираем из некоторого списка выражений только те, показатель степени которых чётный. Для этого мы, во-первых, задаём шаблон для выбора выражений со степенью, _^x_, и во-вторых, задаём условие для отфильтровывания нечётных степеней, EvenQ[x].

    Подробней о шаблонах с условиями см. книги Е. М. Воробьёва [1, с. 152–153] и П. Веллина и др. [14, с. 156–159].

    (рис 10.12) Задание правил преобразования и шаблонов с условиями

    10.2.3. Задание шаблонов-альтернатив

    Если имеется некоторый набор шаблонов, и требуется проверить, соответствует ли то или иное выражение хотя бы одному из них, используются так называемые шаблоны-альтернативы, которые П. Веллин и др. [14, с. 159] определяет как выражения вида patt1|patt2|..., где patt1,patt2,... — независимые шаблоны.

    На рис. 10.13 приведём ряд примеров, аналогичных примерам в работе (П. Веллин и др. [14, с. 160]), которые иллюстрируют возможности применения шаблонов-альтернатив. В примере In[1] мы проверяем, представляет ли собой выражение a^5 символ а, возведённый в целочисленную степень либо символ а, возведённый в вещественную степень. Для полноты иллюстрации в In[2] мы проводим такие же манипуляции с выражением a^5.1. В результате обоих вычислений, как и ожидалось, мы получаем True. В примерах In[3] и In[4] мы проверяем те же выражения на соответствие шаблону "символ a, возведённый в целую или вещественную степень", то есть, задаём альтернативу не для полной формы выражения, а только для показателя степени. В примере In[5] из списка разнотипных данных мы выбираем только те элементы, которые являются целыми или рациональными числами.

    Подробней о шаблонах-альтернативах см. книгу П. Веллина и др. [14, с. 159–161].

    (рис 10.13) Задание и использование шаблонов-альтернатив

    10.2.4. Использование шаблонов в локальных правилах преобразования

    Использование шаблонов в локальных правилах преобразований подробно комметирует Е. М. Воробьёв в своей книге [1, с. 158–162]. Как мы помним из пункта 10.1.2, локальные правила преобразования задаются выражениями вида exprl->expr2 и exprl:>expr2. В настоящем пункте мы научимся задавать локальные правила преобразования, содержащие в выражении expr1 шаблоны. Для этого воспользуемся примером, аналогичным, приведённому в книге Е. М. Воробьёва [1, с. 159–160]. Применим к представляющему собой список выражению {m,n} три разных набора правил подстановки. В примере In[1] на рис. 10.14 зададим правила {m->a,n->b}. Результат преобразований Out[1] достаточно очевиден: m заменено на a, n — на b. В примере In[2] добавим к имеющимся ещё одно правило {m,n}->c. Результирующее выражение Out[2] отличается от Out[1], поскольку последнее правило замены, как оказалось, гораздо больше соответствует преобразуемому выражению.

    Теперь попробуем осуществить ту же замену при помощи шаблонов. Для этого в примере In[3] на рис. 10.14 зададим правило замены в виде {x_,y_}->c.

    Как мы выяснили в примерах In[1] и In[2] на рис. 10.14, в случае, если к некоторому выражению применено несколько правил преобразования, не содержащих шаблоны, то в первую очередь выполняется то, которое больше соответствует изменяемому выражению. Определим, какое из правил будет выполняться, если они содержат шаблоны. В примере In[4] применим к тому же выражению {m,n} набор правил преобразований {{x_,x_}->c,{_,_}->d}. Хотя исходное выражение соответствует обоим шаблонам, преобразование было выполнено по правилу {x_,x_}->c. В примере In[5] поменяем местами правила преобразований в наборе, т.е., зададим {{_,_}->d,{x_,x_}->c}. Результат в Out[4] показывает, что в данном случае была осуществлена замена по другому правилу, {_,_}->d. Следовательно, если изменяемое выражение соответствует нескольким шаблонам в правилах преобразований, выполняется то правило, которое указано раньше остальных.

    (рис 10.14) Использование шаблонов в локальных правилах преобразований

    Специфическим образом осуществляется вычисление функции многократного применения локальных правил преобразований ReplaceRepeated с шаблонами. Эта специфика доступно пояснена в книге Е. М. Воробьёва [1, с. 160]: "…ее [функции ReplaceRepeated] вычисление сводится к повторному вычислению функции ReplaceAll до тех пор, пока ни одно из подвыражений преобразуемого выражения не удается преобразовать в соответствии с хотя бы одним шаблоном списка. При этом порядок применения шаблонов следующий. Первый шаблон списка используется, пока в преобразуемом выражении находится хотя бы одно подвыражение, ему соответствующее. Затем применяется второй шаблон списка и т.д. Ни в коем случае не следует думать, что каждый раз применяется более чем один шаблон списка".

    На рис. 10.15. приведён пример также из книги Е. М. Воробьёва [1, с. 160], иллюстрирующий действие функции ReplaceRepeated. Первый шаблон списка был применён дважды: в результате исходное выражение было сведено к одноэлементному списку {а}. Затем к полученному на предыдущем этапе выражению был применён третий шаблон. Второй шаблон не использовался ни разу, хотя на одном из этапов преобразования и получалось соответствующее ему выражение. После применения третьего шаблона результирующее выражение a оказывается несоответствующим ни одному указанному шаблону, и вычисления прекращаются.

    (рис 10.15) Использование шаблонов при использовании функции многократного применения правил преобразований ReplaceRepeated

    Ключевые термины

    Верхнее значение выражения — это правило преобразования, ассоциированное с находящимся на первом уровне выражения элементом этого выражения.

    Глобальным называется правило преобразования, которое осуществляет заданное преобразование во всём тексте программы.

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

    Нижнее значение выражения — это правило преобразования, ассоциированное с заголовком выражения независимо от его элементов на нижних уровнях.

    Шаблоном является выражение, содержащее символ подчёркивания (выражение Blanc[]).

    Краткие итоги

    В данной лекции мы познакомились с принципами программирования на языке Mathematica в стиле, основанном на использовании правил преобразований. В частности мы с новой позиции познакомились с операциями присваивания и отложенного присваивания, выступающими в роли глобальных правил преобразований. Мы научились осуществлять присваивание абсолютно любым выражениям: обходить запрет на присваивание и задавать верхние и нижние значения выражений. Мы познакомились с принципами задания локальных правил преобразований и их использования в вычислениях. Мы научились избирательно обрабатывать выражения в зависимости от их типа и структуры при помощи шаблонов. Также мы научились применять шаблоны при задании глобальных и локальных правил преобразований.

    Вопросы

  • Какие преобразования называются в Mathematica глобальными? Каким образом задаются глобальные правила преобразований?
  • Для каких целей выражения снабжаются атрибутом Protected? Каким образом атрибут Protected можно убрать из списка атрибутов выражения? Добавить в список?
  • Что такое верхнее значение выражения? Каким образом осуществляется присвоение выражениям верхних значений?
  • Что такое нижнее значение выражения? Каким образом осуществляется присвоение выражениям нижних значений?
  • Какие преобразования называются в Mathematica локальными? Каким образом задаются локальные правила преобразований?
  • Какие выражения в Mathematica называются шаблонами?
  • Чем отличаются друг от друга шаблоны _h и h_?
  • Какие классы выражений выделяют шаблоны с двумя и тремя символами подчёркивания? При работе с каким классом данных их целесообразно использовать?
  • В каких случаях используются шаблоны с условиями? Каким образом они задаются?
  • В каких случаях используются шаблоны-альтернативы? Каким образом они задаются?
  • Упражнения

  • Опишите процесс вычисления следующих наборов выражений (в скобках для проверки указан результат каждого вычисления).
  • x=a;

    y=b;

    x+10/.x->6

    (результат: 16)

  • a=5;

    x:=a;

    y=b;

    a=10;

    x+10/.x->y

    (результат: 20)

  • a=5;

    x=a;

    y=b;

    a=10;

    x+10/.x->y

    (результат: 15)

  • a=c;

    x=a;

    y=b;

    a=10;

    x+10/.x->y

    (результат: 10+b)

  • Set[k,10];

    SetDelayed[l,u];

    ReplaceAll[l^2-k,Rule[k,l]]

    (результат: -10+u^2)

  • Set[n,5];

    SetDelayed[k,n];

    SetDelayed[l,u];

    Set[n,10];

    ReplaceAll[l^2-k,Rule[k,l]]

    (результат: -10+u^2)

  • SetDelayed[n,5];

    Set[k,n];

    Set[l,u];

    Set[n,10];

    ReplaceAll[l^2-k,Rule[k,l]]

    (результат: -5+u^2)

  • SetDelayed[n,v];

    Set[k,n];

    Set[l,u];

    ReplaceAll[l^2-k,Rule[k,l^2]]

    (результат: 0)

  • SetDelayed[n,v];

    Set[k,n];

    SetDelayed[l,u];

    ReplaceAll[l^2-k,Rule[l,k]]

    (результат: -v+v^2)

  • Присвойте выражениям, записанным слева, значения, указанные справа. Для выполнения задания используйте присвоение верхних значений и управление атрибутом Protected.

    k^l 3

    m^2 n^3

    x+y z

    x+y^2 z^2

    Cos[f] g+h

    Cos[f]+g h

    u^Sqrt[v] w

    u^Sqrt[3] w

    Sqrt[3]^u v

  • При помощи задания нижних значений создайте простейшую базу данных, содержащую информацию о сотрудниках вашего отдела/ студентах вашей академической группы/ членах вашей семьи. Занесите в базу следующие сведения: фамилия, имя, отчество, пол, день, месяц и год рождения.
  • Задайте пользовательскую функцию, которая преобразует строку, содержащую только буквы латинского алфавита, в список, элементами которого являются номера этих букв в алфавите. Для выполнения задания используйте функцию Characters, с которой мы познакомились в лекции 3 сего курса, и локальные правила преобразования.
  • Задайте пользовательскую функцию, дублирующую действие встроенной функции Abs. Используйте при задании шаблоны с условиями.
  • Найдите как можно больше шаблонов, которым соответствуют заданные ниже выражения. Проверьте соответствие при помощи функций MatchQ и Cases.

    a^b+2*c

    a^2+b^2

    a^b+b^a

    1+2*I

    {a,b,c}

    {a,{},b,{},c}

    x[t]^y

    x[t]*y[t]

    a^(2*a+3*b)

  • Вернуться к учебному плану