Главная страница

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


Скачать 4.43 Mb.
НазваниеНастоящий учебник посвящен системе Mathematica прикладному пакету компьютерной алгебры, при помощи которого можно решать любые задачи, в которых в той или иной форме встречается математика
АнкорМатематика
Дата11.05.2022
Размер4.43 Mb.
Формат файлаpdf
Имя файла106-108.pdf
ТипУчебник
#521834
страница18 из 38
1   ...   14   15   16   17   18   19   20   21   ...   38
X, Map(Y, Z))
= Map(X
× Y, Z)
= Map(Y, Map(X, Z))
Таким образом, функция f двух переменных находятся в естественном взаимно однозначном соответствии с каждой из двух функций одной переменных, значениями которых являются функции одной переменной.
Однако то, что две вещи находятся в естественном взаимно однозначном соответствии, еще абсолютно не значит, что эти две вещи совпадают и их следует отождествлять! У каждого гражданина имеется единственный пас- порт, а каждый паспорт принадлежит единственному гражданину, но ведь,
как замечает по этому поводу Чжуан Чжоу,
гражданин и паспорт —
это совсем не одно и то же.
Парциальная функции широко используются в математике. Выражение по каждому аргументу относится именно к тем свойствам, которые выра- жаются в терминах парциальных функций. Например, билинейно значит именно линейно по каждому аргументу. Например, если U, V и W — три векторных пространства над полем K, то отображение U
× V −→ W на- зывается билинейным, если все парциальные функции f (u,
), u ∈ U, и
f (
∗, v), v ∈ V , линейны. Аналогично вводится непрерывность по каждому аргументу, дифференцируемость по каждому аргументу и т.д.

226
Поэтому в языке Mathematica необходимо тщательнейшим образом различать функцию f двух аргументов f[x,y] и функцию g(x) одного аргумента g[x][y]. Разумеется, между функциями первого типа и семей- ствами x
7→ g(x) функций второго типа существует естественное взаимно однозначное соответствие. Однако синтаксически это совсем не одно и то же. Более того, во многих случаях, например, когда нам нужно обращаться к функции g[x] по имени — скажем, в командах применения к списку —
или в тех случаях, когда она естественно мыслится как самостоятельная функция, второй формат удобнее. Подчеркнем, что если в первом случае речь идет о техническом удобстве, то во втором случае — всего лишь о психологическом комфорте!! Приведем несколько примеров:
Пусть f — функция одного аргумента. В этом случае мы привыкли интерпретировать выражение f
1
(x) как значение функцию x
7→ f
1
(x),
а не как значение функции (f, x)
7→ f
1
(x). В соответствии с этим приня- то писать InverseFunction[f][x]. Хотя в принципе мы могли бы ввести функцию inversefunction[f ,x ]:=InverseFunction[f][x].
В языке Mathematica log
b
(x) интерпретируется как значение функции двух аргументов, а именно, b (base) и x (или, говоря техническим языком,
одного параметра b и одного собственно аргумента x). Обращение к этой функции происходит в формате Log[b,x]. Однако при этом един- ственный способ обратиться к парциальной функции x
7→ log
b
(x), состоит в том, чтобы вызвать ее как анонимную функцию Log[b,#]&. Однако начинающий, вероятно, будет чувствовать себя комфортнее, дав функции
x
7→ log
b
(x) собственное имя, например, положив log[b ][x ]:=Log[b,x].
Однако с точки зрения Mathematica функции Log и log абсолютно различ- ны!!! Как мы уже знаем, у функции Log два аргумента. Конечно, функция
Log может вызываться и с одним аргументом x, по умолчанию b = e, так что значение Log[x] функции Log в x представляет собой натуральный ло- гарифм числа x. В то же время, у функции log один аргумент, а именно,
b. И ее значение log[b] в b представляет функцию log
b
: x
7→ log
b
(x)!!! В
свою очередь log[b][x] есть значение log
b
в x.
Предостережение. Мы не уверены, что давать собственным функциям имена, лишь в одной позиции отличающиеся от имен встроенных функций, представляет собой бле- стящую идею. Например, попытавшись ввести напечатанный выше текст, вы получите в ответ следующее сообщение: General:
Possible spelling error:
new symbol name
"log" is similar to existing symbol "Log".
Дальше все зависит, конечно, от прису- щего Вам уровня тревожности (anxiety level). Начинающий пользователь, не уве- ренный в том, что он все делает правильно, скорее всего, запаникует и постарается переименовать функцию. Матерый (mature) программист выключит все сообщения об ошибках при помощи команды Off[], а чуть менее циничный выключит только сообще- ние об опечатках посредством Off[General:...]. Мы предпочитаем этого не делать, а просто второй раз нажимаем Shift-Enter, чтобы сообщение об ошибке не записалось в
Notebook. Дело в том, что случайные опечатки в одной букве действительно встречают- ся очень часто!!! Когда Вы вводите log второй раз, система уже воспринимает его как законный символ и больше не жалуется. Тем не менее, мы предпочитаем давать функ- циям имена, отличающиеся от внутренних функций по крайней мере в двух позициях.
Например, если мы хотим дать собственное определение экспоненты — а такое желание

227
у алгебраистов возникает довольно часто!!! — мы называем ее expo, а не просто exp.
Разумеется, все сказанное относится и к функциям трех или большего числа аргументов. Например,
f[x,y,z], f[x,y][z], f[x][y,z] и f[x][y][z]
представляют собой абсолютно различные способы задания функции!!! Не- обходимо четко понимать, что только первая из них представляет собой функцию трех аргументов, вторая — функцию двух аргументов, а третья и четвертая — функции одного аргумента. В свою очередь все эти форматы следует тщательно отличать от функций одного аргумента f[
{x,y,z}], f[{x,y}][z], f[x][{y,z}]!!
Вот наиболее характерные примеры:
Пусть f и g — две функции одного аргумента. В этом случае мы привыкли интерпретировать выражение (f
◦ g)(x) как значение функции
x
7→ f(g(x)), а не как значение функции (f, g, x) 7→ f(g(x)). В соответствии с этим принято писать Composition[f,g][x]. Хотя в принципе мы могли бы ввести функцию трех аргументов compositio[f ,g ,x ]:=Composition[f,g][x].
Функция Nest представляет собой вариант функции Composition, опи- сывающий последовательное применение одной и той же функции f . Од- нако обычно Nest вызывается в формате Nest[f,x,n], где f есть функция,
x — аргумент, значение в котором вычисляется, а n — количество приме- нений функции f . Допустим, мы хотим дать имя функции f
◦n
. Это снова можно сделать при помощи парциальных функций, например, так. Поло- жим iterate[f ,n ]:=Nest[f,#,n]&. Тогда iterate[f,n] как раз и пред- ставляет f
◦n
. Например, iterate[f,5][x] даст нам f[f[f[f[f[x]]]]].
§ 5. Аргументы функций
Будда говорил бхикшу, что благодаря самости могут быть атри- буты самости. Если нет самости, нет атрибутов самости.
Сутра неисчислимых смыслов
Аргументы встроенных функций подразделяются на несколько типов, в зависимости от степени их явности, обязательности, а также возможности
(и желательности!) их изменять:
собственно аргументы,
параметры,
опции,
атрибуты.
Собственно аргументы — это обычные аргументы в математическом по- нимании функции, и все они обязаны явно фигурировать в задании функ- ции в виде Blabla[x,y]. Например, у функций Exp, Cos, Sin, Minus, Not один аргумент, в то время как у функций Subtract, Divide, Power, Implies

228
— два. В случае, если функция вызывается с неправильным количеством аргументов, появится сообщение об ошибке. Ассоциативные алгебраиче- ские операции такие как Plus, Times, And, Or и некоторые другие функции могут иметь любое конечное число аргументов — в том числе не иметь вообще ни одного!
В то же время указание параметров не является обязательным, они могут указываться явно или только подразумеваться. В последнем слу- чае система по умолчанию (by default) выбирает в качестве парамет- ра что-то хорошо ей известное: 0, 1,
{0,1}, 2, 8, 10, 16, 256, E, Pi,
GoldenRatio, Infinity, Integer, Real и тому подобное. Стандартный выбор параметров указывается в полном описании функции. При необхо- димости пользователь может включать явный выбор параметров, отлича- ющихся от стандартных, в тело функции как дополнительные аргументы:
Например, функция Log может вызываться с одним аргументом, в фор- ме Log[x] и в этом случае дает значение натурального логарифма числа
x. В то же время она может вызываться с двумя аргументами (собственно аргументом и параметром!!), в форме Log[b,x] и в этом случае дает лога- рифм числа x по основанию (base) b. Например, Log[2,x] — двоичный логарифм x, Log[10,x] — десятичный и т.д. Иными словами, в этом слу- чае дефолтное значение параметра b равное e, может быть заменено на любое другое допустимое значение этого параметра.
Точно так же функция IntegerDigits может вызываться с одним ар- гументом, в форме IntegerDigits[n] и в этом случае дает список деся- тичных цифр целого числа n. В то же время она может вызываться с двумя или тремя аргументами (собственно аргументом n и одним или дву- мя параметрами!!). Функция IntegerDigits[n,b] вычисляет цифры n по основанию b, а функция IntegerDigits[n,b,m], кроме того, дополняет по- лучающийся список приписывая к нему слева нули до длины m. Иными словами, в этом случае дефолтное значение b равно 10, и — внимание! —
дефолтное значение m равно Length[IntegerDigits[n,b]].
Функция Random вообще не имеет аргументов, а только три параметра:
тип (Head: Integer, Real или Complex),
область изменения (Range),
количество значащих разрядов (Precision),
причем по умолчанию значение Head равно Real, значение Range — [0,1], и значение Precision — MachinePrecision. Иными словами, функция Ran- dom вызванная вообще без аргументов, в форме Random[], даст Вам веще- ственное число от 0 до 1 с 16 значащими цифрами — из которых только 6
отображаются на экране.
В свою очередь опции и атрибуты описывают режим работы функции,
используемые при ее вычислении параметры, тождества и процедуры и то- му подобное. Они имеют стандартные настройки (default settings,
factory defaults).
Все эти настройки можно менять, опции меняются

229
при помощи специальной конструкции Rule, посредством включения тек- ста Option->Choice в тело функции, а атрибуты — внешним образом при помощи специальных команд таких как SetAttributes.
Если Вы хотите убедиться в том, что выбрана фабричная установка опции, можно явным образом задать правило Option->Automatic, кроме того, возможны варианты Option->None, Option->All и десятки других.
Во многих случаях (в первую очередь при выводе графики) выбор опций диктуется исключительно эстетическими соображениями. Например, по умолчанию картинка выводится в формате 1:GoldenRatio:
Иными словами, дефолтная установка состоит в задании трансфор- мационного правила AspectRatio->1/GoldenRatio, дающего стандартный альбомный формат (landscape orientation).
Задание правила AspectRatio->GoldenRatio)) порождает картинку в стандартном книжном формате (portrait orientation).
В то же время, будучи математиками, а не книгоиздателями, при выводе графики авторы предпочитают пользоваться одной из следующих устано- вок:
Правилом AspectRatio->1, приводящим к тому, что картинка вписы- вается в квадрат;
Правилом AspectRatio->yscale/xscale, приводящим к одинаковому масштабу по осям x и y;
Правилом AspectRatio->Automatic, приводящим к одинаковому мас- штабу по осям x и y или, в случае невозможности этого, наиболее удовле- творительному с точки зрения системы результату.
Изменить атрибуты встроенной функции Blabla сложнее, для этого нужно проделать ритуальную последовательность телодвижений, начина- ющуюся с Unprotect, ClearAttributes или чего-нибудь в таком духе. Это значит, что подразумевается, что пользователь не обязан задавать их —
не должен задавать их — а во многих случаях он будет гораздо здоровее,
если вообще не подозревает об их существовании!! Дело в том, что изме- нение атрибутов встроенных функций может легко привести к серьезным конфликтам и артефактам при выполнении вычислений, бесконечной ре- курсии и т.д. Поэтому — unless you really know what you are doing —
даже не пытайтесь менять атрибуты встроенных функций. Более того, обыч- но в этом нет никакой нужды, гораздо проще ввести новую функцию с тем же определением, но с другим именем и изменить атрибуты у этой новой функции!! Чтобы у неопытного пользователя и не возникало желания иг- рать с определениями и настройками, встроенные функции имеют атрибут
Protected. Парадокс Рассела: Attributes[Protected]===
{Protected}.
Укажем несколько обычных соглашений, связанных с только что опи- санной иерархией аргументов встроенных функций:
В большинстве случаев первыми указываются основные аргументы функции и только потом параметры.

230
Впрочем, это правило используется только в тех случаях, когда оно не входит в конфликт с традиционными математическими обозначениями.
Если в традиционном математическом обозначении параметры указы- ваются как индексы, то параметры предшествуют основным аргументам.
Например, log
b
(x) записывается как Log[b,x], а вовсе не как Log[x,b].
В случае, когда в стандартном обозначении функции фигурируют как верхние, так и нижние индексы, нижние индексы, как правило, предше- ствуют верхним. Например, многочлен Лежандра P
m
n
(x) обозначается через LegendreP[n,m,x].
В ответе на информационный запрос ?Blabla перечисляются все аргу- менты и параметры функции с именем Blabla.
В ответе на информационный запрос ??Blabla, кроме того, перечис- ляются все опции и атрибуты функции с именем Blabla.
§ 6. Алгебраические операции
Напомним, что (внутренней, бинарной, всюду определенной) ал- гебраической операцией на множестве X называется отображение
f : X
× X −→ X, (x, y) 7→ f(x, y).
По умолчанию мы будем называть такие отображения просто операци- ями или законами композиции (Verkn¨
upfung). При этом x и y назы- ваются операндами, а f (x, y) — результатом операции. В старинных книжках алгебраические операции назывались еще действиями — четы- ре действия арифметики: служение, почитание, угождение и давление
— однако мы используем термин действие (action) исключительно в точ- ном техническом смысле: действие чего-то на чем-то.
Для алгебраических операций традиционно применяется несколько раз- личных способов записи. Вот некоторые наиболее распространенные:
Такая запись, когда знак операции пишется между операндами, назы- вается инфиксной. Такая запись операций применяется особенно часто:
x
• y, x + y, x − y, x · y, x/y, x ◦ y, x ∪ y, x ∩ y, x ∨ y, x ∧ y, x ↑ y и т.д.
Часто применяются другие записи алгебраических операций, скажем,
префиксная, когда знак операции пишется перед операндами. Обыч- но используется функциональная запись f (x, y). Однако в этом случае можно обойтись вообще без скобок и писать f xy. Эта форма записи, на- зываемая по-научному префиксной операторной записью, в быту из- вестна как запись Лукасевича, а в литературе для младших школьников как польская запись. Она весьма обычна в логике и Computer Science,
но алгебраисты практически никогда ей не пользуются.
Во многих старых микрокалькуляторах использовалась постфиксная запись, когда знак операции вводится после операндов. В популярной ли- тературе такая запись обычно называется обратной польской записью.

231
В многих случаях традиционно используется циркумфиксная запись,
которая охватывает операнды с двух сторон (сочетание совместно рабо- тающих префикса и постфикса), скажем, [x, y], (x, y) и т.д.
Часто используется также экспоненциальная запись x
y
, и другие двумерные формы записи.
В настоящем курсе при обсуждении математических понятий мы в со- ответствии с алгебраической традицией пользуемся почти исключительно инфиксной записью x
∗ y. В то же время на уровне программирования мы попеременно пользуемся инфиксной записью, которую в языке Mathema- tica принято называть операторной или сокращенной, и префиксной записью f (x, y), которую в языке Mathematica принято называть функ- циональной или полной.
В дальнейшем мы будем часто ссылаться также на некоторые важней- шие тождества для алгебраических операций.
Операция называется ассоциативной, если (x∗y)∗z = x∗(y ∗z) для любых x, y, z
∈ X. В функциональной записи это тождество принимает форму f (f (x, y), z) = f (x, f (y, z)). В Mathematica ассоциативность опера- ции f выражается атрибутом Flat. Этот термин связан с тем, что любое выражение, составленное из последовательных применений f , ну, скажем,
f[f[x1,f[f[x2,x3],x4]],x5], может выровнено (flattened), т.е. сведено к форме f[x1,...,xn], в данном случае f[x1,x2,x3,x4,x5].
Операция называется коммутативной, если x ∗ y = y ∗ x для лю- бых x, y
∈ X. В функциональной записи это тождество принимает форму
f (x, y) = f (y, x).
В Mathematica коммутативность операции f выража- ется атрибутом Orderless. Для операций, обладающих этим атрибутом,
переменные автоматически сортируются, иными словами f[y,x] преобра- зуется в f[x,y]. Если операция одновременно ассоциативна и коммутатив- на, то же самое относится к любому числу переменных, иными словами f[y,x,u,v] будет преобразовано в f[u,v,x,y].
Говорят, что e — левый нейтральный элемент относительно , если
e
∗ x = x для любого x ∈ X. Аналогично определяется правый ней- тральный элемент e, для которого x
∗ e = x для всех x ∈ X. Элемент
e
∈ X называется нейтральным элементом операции , если он является как левым, так и правым нейтральным. Например, 0 является нейтраль- ным элементом относительно сложения, 1 — относительно умножения, а тождественное отображение id — относительно композиции. Если опера- ция f одновременно ассоциативна и обладает нейтральным элементом e,
то в Mathematica обычно придается смысл результату применения этой операции к любому количеству аргументов. А именно, в этом случае f[]
истолковывается как e, а f[x] — как x. Второе из этих свойств выражается атрибутом OneIDentity.
Нам будет часто встречаться еще два важнейших тождества, в которых участвуют две алгебраических операции. Рассмотрим множество X с опе- рациями
и .

232
Определенная на множестве X операция называется дистрибутив- ной слева относительно
, если x ∗ (y ◦ z) = (x ◦ y) (x ◦ z) для любых
x, y, z
∈ X.
Операция называется дистрибутивной справа относительно , ес- ли (x
◦ y) ∗ z = (x ◦ z) (y ◦ z) для любых x, y, z ∈ X.
Если
дистрибутивно относительно как слева, так и справа, говорят о двусторонней дистрибутивности или просто о дистрибутивности

относительно
. Если операция коммутативна, то для проверки дистри- бутивности
относительно достаточно проверить одностороннюю дис- трибутивность. Например, умножение чисел дистрибутивно относительно сложения: x(y + z) = xy + xz и (x + y)z = xz + yz. В то же время, потенци- рование часто бывает дистрибутивным относительно умножения справа, в том смысле, что (xy)
z
= x
z
y/z, но трудно ожидать, чтобы оно было дистри- бутивно относительно умножения слева, т.е. чтобы выполнялось тождество
x
yz
6= x
y
x
z
Каждый, кто серьезно пытается понять работу системы Mathematica,
должен как можно раньше освоиться с мыслью, что в отличие от ассоци- ативности и коммутативности дистрибутивность никогда не приме- няется автоматически ни в одну, ни в другую сторону!!! Вместо того, чтобы оценивать, правильно это или нет, стоит вначале задуматься над тем, с чем это связано. Дело в том, что любое применение дистри- бутивности рассматривается как нетривиальное изменение фор- мы выражения. В первую очередь это связано с тем, что применение ассоциативности и/или коммутативности не требует значительных затрат времени или памяти и приводит к результату предсказуемой сложности.
Для применения дистрибутивности это совершенно не так!!! Для того, что- бы убедиться в этом, достаточно взглянуть на следующие примеры:
Попытайтесь раскрыть скобки в чем нибудь совсем простеньком, ну,
хотя бы в (x + y)
100000
— раскрытие скобок это в точности применение дис- трибутивности слева направо. На нашем компьютере выполнение операции
Expand[(x+1)^100000] занимает около секунды. Но главным соображени- ем с точки зрения конструкторов системы Mathematica, как нам кажется,
было следующее: длина (x+y)^100000 равна 2, в то время, как длина Ex- pand[(x+y)^100000] равна 100001, не говоря уже про размер коэффициен- тов. А если еще чуток увеличить экспоненту? Ясно, что автоматическое раскрытие скобок в таких случаях привело бы к еще гораздо большему разбуханию промежуточных результатов, чем то, которое наблюдается в действительности.
Ну а про применение дистрибутивности в обратную сторону и гово- рить нечего!!! В частном случае сложения и умножения применение дис- трибутивности справа налево представляет собой задачу разложения мно- гочленов на множители. Известно, что это непростая задача. Попробовав решить ее с показателями такого-же порядка, как в предыдущем приме- ре, мы сразу получим задачку, решение которой при помощи сегодняшних

233
алгоритмов может занять довольно значительное время. Поэтому скорее всего результатом такой попытки будет сообщение: function:
Exponent is out of bounds for function Factor.
Но дело, опять же даже не в этом, а в том что при разложении на множители длина выражения то- же может чудовищным образом увеличиваться! Например, длина выраже- ния x^100000-y^100000 равна 2, но вот длина выражения (x-z1*y)...(x- z100000*y), получающегося после его разложения на множители в коль- це
C[x, y], равна 100000. Ну а разложение столь крошечной вещи, как
x
200
− y
200
на множители над кольцом
Z[i] целых гауссовых чисел зани- мает считанные секунды!!
Применение дистрибутивности слева направо, т.е. раскрытие скобок,
производится при помощи команды Distribute. Для различных конкрет- ных ситуаций оно производится также при помощи более сильных команд
Expand, PowerExpand и других, которые раскрывают скобки и, кроме того,
обычно делают еще кое что. Точно также применение дистрибутивности справа налево осуществляется либо при помощи специальных команд та- ких как Factor, либо при помощи правил преобразования, которые мы обсуждали в Главе 2:
In[1]:=
{(a+b)*c,Expand[(a+b)*c],a*c+b*c,Factor[a*c+b*c]}
Out[1]=
{(a+b)*c,a*c+b*c,a*c+b*c,(a+b)*c}
In[2]:=
{(a^c*b^c,(a*b)^c, PowerExpand[(a*b)^c]}
Out[2]=
{a^c*b^c,(a*b)^c,a^c*b^c}
§ 7. Арифметические операции
The different branches of Arithmetic — Ambition, Distraction, Uglifi- cation and Derision.
Lewis Carroll
Простейшими алгебраическими операциями являются арифметические операции над числами. В системе Mathematica они имеют обычный смысл,
но применяются к также к многочленам, рациональным дробям, векторам,
матрицам, etc., etc., etc.
x+y+z
Plus[x,y,z]
сложение
-x
Minus[x]
переход к противоположному x-y
Subtract[x,y]
вычитание x*y*z
Times[x,y,z]
умножение x/y
Divide[x,y]
деление x^y
Power[x,y]
потенцирование
Как всегда, начнем с нескольких важнейших синтаксических моментов. В
языке Mathematica различие между оператором и функцией является чи- сто лингвистическим и начинающему нет нужды в него вникать. Сокра- щенная инфиксная запись алгебраических операций в виде x
•y с использо-

234
ванием специальных символов +,-,*,/,^ рассматривается как оператор- ная запись, в то время как полная запись вида f [x, y] — как функци- ональная запись. Отметим, что знание полных функциональных назва- ний арифметических операций совершенно необходимо, если Вы собирае- тесь обращаться к ним при написании программ. Вот простейший пример:
Apply[Plus,x] вычисляет сумму элементов списка x, а Apply[Times,x] —
произведение элементов этого списка. При описании свойств этих операций мы часто будем пользоваться их полными названиями. Отметим некоторые особенности использования арифметических операций в системе Mathema- tica.
Умножение в языке Mathematica выражается посредством либо про- бела. Таким образом, как x*y, так и x y обозначают произведение x и y.
В то же время xy без пробела представляет собой не произведение x и y, а новую переменную, с именем "xy".
Хороший стиль программирования.
Для лучшей читаемости про- грамм и уменьшения вероятности возникновения ошибок никогда не обо- значайте умножение пробелом!!! В самом начале использования си- стемы Mathematica смешение x y и xy было для нас одним из заметных источников ошибок. Никогда не ленитесь напечатать лишнюю
. Сейчас мы ставим
даже в тех случаях, когда синтаксически для обозначения умножения не требуется никакого знака. Например, 2x автоматически ис- толковывается как 2*x, x(y+z) — как x*(y+z), а x^yz — как x^y*z. Тем не менее, мы призываем читателя, особенно начинающего, ставить
даже в таких случаях!!!
Использование для обозначения умножения не может принести никакого вреда, в то же время пропуск там, где она нужна, может привести к серьезной ошибке.
В InputForm для обозначения потенцирования используется не экспо- ненциальная x
y
, а инфиксная запись x^y. Nothing special: использование инфиксной записи для обозначения потенцирования типично для всех язы- ков программирования.
Комментарий. В большинстве языков потенцирование обозначается x
y, но, к сожале- нию, не на всех клавиатурах есть знак
. Поэтому в Mathematica используется TEX'овское обозначение ˆ. Через палитры начинающий может при желании вводить потенцирование в TraditionalForm, т.е. в экспоненциальной записи. Однако мы решительно не рекомен- дуем это делать! Во первых, это просто медленнее, а, во-вторых, как и любой неявный формат, значительно менее удобно во всех отношениях, в том числе с точки зрения согласования с другими программами и дальнейшей работы с текстом.
Основные арифметические операции Plus, Times и Power имеют ат- рибут OneIdentity.
Это значит, что их можно вызвать с одним аргу- ментом, причем Plus[x]===x, Times[x]===x и Power[x]===x. Более то- го, Plus, Times и Power можно вызвать вообще без аргументов, при этом,
естественно, Plus[]===0, Times[]===1 и Power[]===1.
Следующий ключевой вопрос состоит в том, как истолковывается вы- ражение x
yz в общем случае? Ответ состоит в том, что разные опера- торы используют разную группировку. Вот три основных возможно-

235
сти:
Операция
ассоциативна. Мы уже знаем, что в этом случае x•y•z =
(x
• y) • z = x • (y • z). К этому типу относятся функции Plus и Times. А
именно, они имеют атрибут Flat (ассоциативность) — и, кроме того, ат- рибут Orderless (коммутативность). Это значит, что их можно вызвать с любым количеством аргументов, причем ни расстановка скобок, ни по- рядок аргументов не имеют никакого значения, Plus[Plus[z,x],y] значит ровно то же самое, что Plus[x,y,z]. Позже мы поговорим об изменении атрибутов, которым можно заставить систему думать, что это не одно и то же!
Для операции
используется левая группировка. В этом случае в выражении x
• y • z по умолчанию применяется левонормированная рас- становка скобок, (x
• y) • z. Операции Subtract и Divide относятся к этому типу. Это значит, что x-y-z равно (x-y)-z — в действительности, это некоторое упрощение, через мгновение мы увидим, что как то, так и дру- гое автоматически истолковывается как x+(-1)*y+(-1)*z. Точно так же,
x/y/z равно (x/y)/z или, что то же самое, x/(y*z) — снова это заведомое упрощение, внутренняя форма всех этих выражений x*y^(-1)*z^(-1).
Для операции
используется правая группировка. В этом случае в выражении x
• y • z по умолчанию применяется правонормированная расстановка скобок, x
(y • z). К этому типу относится операция Power,
которая, естественно, не имеет атрибутов Flat, (2 2
)
3
6= 2
(2 3
)
, и Orderless,
2 3
6= 3 2
. Так вот, не только x^y^z автоматически истолковывается как x^(y^z). В действительности в этом случае можно сказать значительно больше: функцию Power можно вызвать с любым количеством аргументов!
При этом по умолчанию выражение Power[x,y,z] истолковывается как
Power[x,Power[y,z]].
В отличие от сложения, умножения и возведения в степень, вычита- ние и деление не рассматриваются как самостоятельные опера- ции. Так, например, спросив FullForm[Subtract[x,y]], Вы получите в ответ Plus[x,Times[-1,y]]. Кстати, это значит, что FullForm[Minus[x]]
имеет вид Times[-1,x]. Совершенно аналогично FullForm[Divide[x,y]]
дает Times[x,Power[y,-1]]. В то же время записи Plus[x,y], Times[x,y]
и Power[x,y] представляют собой полные формы. Таким образом, Sub- tract, Minus и Divide используются исключительно в качестве сокраще- ний для удобства ввода. В частности это значит, что функции Subtract и Divide могут быть вызваны только с двумя аргументами, а функция
Minus — только с одним аргументом.
Все арифметические операции имеют атрибут Listable. Это значит,
что их можно применять к векторам, матрицам и т.д., причем они дают поэлементные операции:
{x,y}+{u,v} совпадает с {x+u,y+v}; {x,y}*{u,v}
— с
{x*u,y*v}, {x,y}^{u,v} — с {x^u,y^v} и т.д.
Предостережение. В частности, для матриц x*y представляет собой умножение по
Адамару, а вовсе не обычное матричное умножение!!! Умножение матриц (и, в частно-

236
сти, эвклидово скалярное произведение векторов) обозначается через x.y или, в полной форме, Dot[x,y]. Точно так же Power[x,n] выражает n-ю степень матрицы x по Адама- ру, а вовсе не ее обычную n-ю степень, которая обозначается MatrixPower[x,n]. Одна из самых типичных ошибок при проведении вычислений в линейной алгебре состоит в том,
что начинающие используют функции, определенные в терминах поэлементного умно- жения Times, вместо соответствующих функций, определенных в терминах матричного умножения Dot, скажем Exp[x] вместо MatrixExp[x]. Точно также совершенно недопу- стимо путать Times с векторным умножением x
×y, или, в полной форме, Cross[x,y].
Некоммутативное умножение. Во многих разделах математики систематически ис- пользуются некоммутативные операции. Умножение
можно сделать некоммутативным
— а при желании даже неассоциативным — при помощи команд:
ClearAttributes[Times,Orderless] и ClearAttributes[Times,Flat].
Эти команды действует только на протяжении одной сессии и даже в пределах этой сессии удаленные атрибуты можно снова вернуть командами
SetAttributes[Times,Orderless] и SetAttributes[Times,Flat].
Кроме того, в ядре системы Mathematica имеется операция NonCommutativeMultiply[x,y]
имеющая также сокращенное обозначение x**y. По умолчанию эта операция предпола- гается ассоциативной, но не коммутативной.
§ 8. Приоритет!!!
I'm not tense, just terribly A*L*E*R*T!!
American proverb
Рассмотренный нами вопрос группировки произведения x
• y • z явля- ется частным случаем более общей проблемы приоритета (precedence)
выполнения арифметических операций. Mathematica использует обычную иерархию арифметических операций: все возведения в степень выполня- ются до умножений и делений, а все умножения и деления — до сложений и вычитаний. Таким образом, x-y^zw будет будет автоматически истолко- вано как x-((y^z)w).
Стоит отметить, что арифметические операции стоят довольно высоко в общей иерархии операций.
Выше них стоят только атомарные выра- жения, операции, связанные с определением или применением функций,
факториалы, некоммутативные умножения и некоторые другие операции.
В порядке убывания приоритета общая иерархия операций в Mathemati- ca выглядит примерно так (исчерпывающее описание порядка выполнения всех операций приведено в таблице в секции A.2.7 книги Вольфрама):
атомы (числа, символы и стринги);
слоты # и бланки ;
импорт файлов <<;
квадратные скобки f[x] и x[[i]];
инкремент и декремент ++, --;
префиксные и инфиксные применения функций @, @@, /@, //@,
,
etc.;
факториал !;

237
дифференцирование Derivative;
потенцирование ^, Sqrt, etc;
интегрирование Integrate и вычисление частных производных D;
некоммутативное умножение **;
векторное умножение Cross;
матричное умножение Dot;
деление /;
умножение *;
сложение +, -, etc.;
отношения ==, !=, <, ,=, >, >=, etc.;
отношения ===, =!=, Element, etc.;
кванторы ForAll, Exists;
отрицание Not
логические операции &&, Xor, ||, Implies, etc.;
паттерны и условия :, /;, etc.;
подстановки, правила, замены ->, :>, /., //., etc.;
модификации значения переменной +=, -=, *=, /=;
чистые функции &;
постфиксное применение функции //;
присваивания и тяги =, :=, ^=, ^:=, /:, =.;
экспорт в файл >>, >>>;
последовательность команд ;.
Эти приоритеты выбраны так, чтобы грамотному пользователю не при- шлось ставить чрезмерное количество явных скобок в своих программах.
Упражнение. Стобы убедиться в том, что Вы поняли, что такое приори- тет, ответьте, не включая компьютер, на следующие вопросы:
Что даст исполнение программы i=1; Sin[i++]?
Что даст исполнение программы i=1; j=i+=1?
Как истолковывается x!y? Почему?
Через месяц интенсивного использования программы (или около того!) у
Вас выработается достаточно отчетливое понимание того, в каком порядке выполняются операции и когда нужно ставить круглые скобки, убеждаю- щие систему отступить от своих априорных представлений. Тем не менее,
нельзя гарантировать, что Вы не сделаете ошибку в случае редко встре- чавшихся Вам команд или конструкций!!!
Хороший стиль программирования.
Для лучшей читаемости про- грамм и уменьшения количества ошибок в сомнительных случаях всегда ставьте скобки!!!! Когда мы начинали использовать систему Mathematica,
мы часто не ставили скобок в таких выражениях, как x/y*z — а, кстати,

238
что такое x/y*z??? Действительно ли это x/(y*z), как было задумано,
или, все же (x/y)*z и, тем самым, равно (x*z)/y. Чтобы ответить на этот вопрос, нужно вспомнить, что внутренняя форма выражения x/y*z имеет вид x*y^-1*z. Но, во-первых, иногда бывает трудно вспомнить то,
чего не знаешь (it takes a long time to find a black cat in a dark room, if it isn't there — Конфуций), и, во-вторых, не вспоминать же это каждый раз!!
Поэтому никогда не ленитесь напечатать еще одну пару скобок!!!
Постановка лишней пары скобок стоит доли секунды, поиск ошибки из-за пропуска пары скобок в сложной программе обычно продолжается гораздо дольше.
§ 9. Итераторы
Одна старуха от чрезмерного любопытства вывалилась из окна,
упала и разбилась. Из окна высунулась другая старуха и стала смотреть вниз на разбившуюся, но от чрезмерного любопытства тоже вывалилась из окна, упала и разбилась. Потом из окна вы- валилась третья старуха, потом четвертая, потом пятая. Когда вывалилась шестая старуха, мне надоело смотреть на них.
Даниил Хармс, `Вываливающиеся старухи'
Допустим, мы хотим ввести многочлен f
n
(x) = 1 + x + x
2
+ . . . + x
n
,
основной вопрос, который фактически возникает в этом контексте у начи- нающих, состоит в том, как ввести многоточие? Иными словами, как по- вторить какую-то операцию много раз?? В Mathematica существует много различных ответов на этот вопрос, отличающихся по синтаксису и исполь- зованию: явные формулы, рекурсия, применение функции к списку, мно- гократная композиция, организация циклов и т.д.:
Циклоидный программист старой школы, находящийся под одурмани- вающим влиянием стиля ПошелНа, скорее всего, организует цикл:
faa[n ][x ]:=Block[
{i,y=1},For[i=1,i<=n,i++,y=y+x^i];Return[y]],
Безнадежно плохо — и тому, кто так понимает программирование, уже ничем не поможешь. Конечно, в этом примере цикл тоже является реше- нием, но в большинстве случаев это худшее из всех возможных решений,
с точки зрения написания программы, а часто и с точки зрения времени исполнения!!!
Наивный, но неиспорченный цивилизацией пользователь (ну, скажем,
профессиональный математик) задаст функцию f
n
рекурсией:
fbb[0][x ]=1; fbb[n ][x ]:=fbb[n-1][x]+x^n.
Этот стон у них песней зовется, мы сами начинали именно с такого стиля программирования, дурное дело нехитрое. Более того, подобный дубо- ломный стиль работает, ему вообще не нужно учиться и на большинстве учебных примеров время исполнения подобных программ мало отличается от сотых долей секунды. Однако не забудьте установить
$RecursionLimit=Infinity!!!

239
Продвинутый программист, воспитанный на λ-исчислении, Lisp, C++ и
Java, задаст ту же функцию в стиле функционального программирования:
fcc[n ][x ]:=Nest[Expand[1+x#]&,1,n]
Стильно, эффектно, демонстрирует понимание того, как работают Nest и Function, и, конечно, несколько лучше, чем fdd[n ][x ]:=Expand[Nest[(1+x#)&,1,n]]
но все равно безнадежно медленно!!!
Однако тот, кто реально овладел концептуальным стилем програм- мирования, свойственным системе Mathematica, знает, что простейшим ответом на большинство подобных вопросов — ответом, который уже на порядке n = 10000 работает в тысячи раз быстрее всех предыдущих —
является использование итеративных конструкций Table, Array, Sum,
Product, основанных на работе со списками. Иными словами, правильным способом определить f
n
(x) является бесхитростное fee[n ][x ]:=Sum[x^i,
{i,0,n}]
Или, на худой конец, организация цикла, исполненного с помощью Do —
раза в четыре медленнее, чем работа со списком, но в сотни раз быстрее,
чем цикл, организованный с помощью For, While или чего-нибудь в таком духе!!! Общим для всех этих конструкция является задание итераторов,
описывающих то, по какой переменной, начиная с какого значения, до како- го значения, и с каким шагом происходит повторение операции. Итераторы задаются в одном из следующих форматов:
{n}
повторить n раз не инкрементируя переменных
{i,n}
инкрементировать i от 1 до n с шагом 1
{i,m,n}
инкрементировать i от m до n с шагом 1
{i,m,n,d}
инкрементировать i от m до n с шагом d
{i,k,l},{j,m,n}
для каждого i от k до l
инкрементировать j от m до n
Мы считаем, что в большинстве случаев правильно задавать итераторы в формате
{i,m,n}, явно указывающем переменную, по которой происходит итерирование, ее начальное и конечное значение. При этом по умолча- нию при каждом вызове переменной ее значение увеличивается на 1. Мы обычно задаем итераторы именно таким образом даже в том случае, когда начальное значение равно 1 так что формально вместо
{i,1,n} было бы печатать просто
{i,n}. Во-первых, мы считаем, что явное задание началь- ного значения итератора в виде
{i,1,n} большей степени соответствует математическим традициям, а, во-вторых, получающаяся при этом про- грамма легче читается. При задании итератора в формате
{i,m,n,d} на каждом шаге происходит инкрементация на d.

240
Вот три важнейших команды, использующие итераторы в таком форма- те
Table[a[i],
{i,m,n}]
вектор (a
i
) с компонентами a
i
Table[a[i,j],
{i,k,l},{j,m,n}] матрица (a
ij
) с коэффициентами a
ij
Sum[a[i],
{i,m,n}]
сумма
n
P
i=m
a
i
Product[a[i],
{i,m,n}]
произведение
n
Q
i=m
a
i
Как видно следующего диалога, функции Sum и Product действуют обыч- ным образом:
In[3]:=Sum[Cos[n*x],
{n,1,5}]
Out[3]=Cos[x]+Cos[2*x]+Cos[3*x]+Cos[4*x]+Cos[5*x]
In[4]:=Product[x-a[i],
{i,1,5}]
Out[4]=(x-a[1])(x-a[2])(x-a[3])(x-a[4])(x-a[5])
Пожалуй одна из самых замечательных особенностей этих функций состо- ит в том, что в качестве начального и/или конечного значения итератора в этих функциях можно взять -Infinity и Infinity. Например, как вы- числение
Sum[1/n^2,
{n,1,Infinity}]
так и вычисление
Product[(1-1/Prime[n]^2)^-1,
{n,1,Infinity}]
даст Pi^2/6. Таким образом, Mathematica знает, чему равно значение ζ(2),
в том числе в форме Эйлеровского произведения!
§ 10. Делимость целых чисел
Несколько важнейших алгебраических операций определяются в терми- нах делимости целых чисел. В действительности, большая часть вычисле- ний бесконечной точности с большими числами основана на использовании модулярной арифметики, т.е. вычислениями не с самими этими числами, а с их остатками по нескольким взаимно простым модулям.
Как известно, правильной формой деления целых чисел является деле- ние с остатком. А именно, для любых целых чисел n, m таких, что m
6= 0,
существуют единственные целые q, r, такие, что n = qm + r и 0
≤ r < |m|.
Такое q называется неполным частным (quotient) при делении n на m,
а r — остатком (remainder)
Предостережение. Неполное частное (quotient) целых чисел n, m не следует путать с их частным (ratio) n/m. Единственность здесь достигается за счет того, что здесь мы отступаем от обычного определение деления с остатком в эвклидовых кольцах, добавляя условие положительности остатка!! Ясно, что для общих эвклидовых колец требование положительности остатка абсолютно бессмысленно. На самом деле, обычно на остаток накладывается более слабое условие
|r| < |m|, в этом случае в кольце целых чисел Z мож- но гарантировать лишь, что существует не более двух пар (q, r) таких, что n = qm + r,

241
причем это свойство вместе с неединственностью остатка однозначно характеризует кольцо
Z. В действительности единственными эвклидовыми кольцами, в которых де- ление с остатком выполняется единственным образом, являются кольца многочленов от одной переменной над полем.
Кроме обычных арифметических операций в кольце целых чисел опреде- лены еще две важнейшие арифметические операции, сопоставляющие двум целым числам их неполное частное и остаток.
Mod[n,m]
остаток при делении n на m
Quotient[n,m]
неполное частное при делении n на m
Функция Mod может вызываться не только с двумя, но и с тремя аргумен- тами, в формате Mod[n,m,d]. В этом случае она возвращает не наименьший положительный остаток, а остаток в полуинтервале [d, d + m).
Математики часто применяют деление с остатком не только для целых,
но и для вещественных чисел, Например, часто используются факторгруп- пы аддитивной группы вещественных чисел
R
+
по модулю 1 или по мо- дулю 2π.
Ни один из аргументов функции Mod не обязан быть целым числом Mod[7*Pi,E] даст -8*E+7*Pi. Тем не менее, предполагается, что аргументы Mod являются числами. Например, ничего не даст попытка вы- числить Mod[x^2,x^2+1], чтобы получить результат в этом случае, вместо
Mod нужно использовать функцию полиномиального деления с остатком
PolynomialMod.
Мы уже упоминали, что в Mathematica имплементировано большое ко- личество теоретико-числовых функций. Упомянем лишь некоторые наибо- лее простые из них. Следующая группа функций связана с вычислением наибольшего общего делителя и наименьшего общего кратного.
GCD[l,m,n]
наибольший общий делитель l, m, n
LCM[l,m,n]
наименьшее общее кратное l, m, n
ExtendedGCD[l,m,n]
линейное представление gcd(l, m, n)
Снова эти функции не работают для многочленов, где нужно использовать функции PolynomialGCD и PolynomialLCM.
Следующие функции связаны с делителями, в частности простыми де- лителями целых чисел.
Divisors[n]
список делителей n
DivisorSigma[n]
сумма делителей n
FactorInteger[n]
разложение n на простые множители
Однако в действительности уже для чисел с несколькими десятками цифр факторизация представляет абсолютно небанальную задачу Мы подробно обсуждаем связанные с этим вопросы в других местах учебника.

242
§ 11. Сравнение вещественных чисел
Следующие функции связаны с обычным порядком на множестве веще- ственных чисел.
Max[x,y,z]
максимум x, y, z
Min[x,y,z]
минимум x, y, z
Abs[x]
абсолютная величина x
Sign[x]
знак x
Отметим несколько особенностей этих функций. По умолчанию Max и
Min интерпретируют свои аргументы как вещественные числа! Если Вы попытаетесь вызвать эти функции с символьными переменными или ком- плексными числами, результатом будет отказ системы возвратить значение функции или сообщение об ошибке. Абсолютная величина интерпретиру- ется обычным образом, как Abs[x]=Max[x,-x]. Знак принимает три воз- можных значения
{−1, 0, 1}, а именно,
sign(x) =





1 при x < 0,
0
при x = 0,
1
при x > 0.
В ядре системы Mathematica определены и все обычные функции округле- ния до ближайшего целого.
Floor[x]
bxc
пол x
Ceiling[x]
dxe = −b−xc потолок x
Round[x]
ближайшее к x целое
IntegerPart[x]
целая часть x
FractionalPart[x]
дробная часть x
За одним исключением использование этих функций ясно из их названия.
Отличие же между функциями Floor и IntegerPart состоит в следующем.
Функция Floor[x], которую принято обозначать
bxc, возвращает наиболь- шее целое, не превосходящее x. Это то, что называется целой частью числа x и традиционно обозначалось [x] или Ent(x) (антье). В то же вре- мя функция IntegerPart в отличие от функции Floor игнорирует знак числа x. Это значит, что для отрицательных чисел IntegerPart[x] рав- но -Floor[-x]. Таким образом IntegerPart[x] соврадает с Floor[x] для
x > 0 и с Ceiling[x] для x < 0.
§ 12. Предикаты
В математике предикатом называется функция, принимающая значе- ние в множестве Booleans=
{True,False}. Однако в языке Mathematica предикатами называются только предикаты от одного аргумента, в то вре- мя как предикаты от двух аргументов называются отношениями. Нам уже

243
встречался предикат AtomQ. Вот еще несколько важнейших относящихся к числам предикатов, которые реализованы в ядре Mathematica:
IntegerQ[x]
целочисленность x
EvenQ[x]
четность x
OddQ[x]
нечетность x
PrimeQ[x]
простота x
NumberQ[x]
x является явно заданным числом
NumericQ[x]
x является числом
MachineNumberQ[x]
x является машинным числом
За исключением двух последних предикатов их пафос абсолютно поня- тен исходя из названий:
IntegerQ[x] спрашивает, имеет ли x формат целого числа. Тем са- мым, IntegerQ[1] возвращает значение True, в то время как IntegerQ[1.]
— False. В самом деле, 1. является не целым, а приближенным веществен- ным числом, оно только кажется целым (wonderful day, it's your hangover that makes it seem terrible).
EvenQ[n] спрашивает, четно ли целое число n. Тем самым, EvenQ[n]
возвращает значение True, если n четно и False, если n нечетно. В свою очередь, OddQ[n] поступает ровно противоположным образом — хотя до- биться от системы явного утверждения, что EvenQ[n] всегда совпадает с
Not[OddQ[n]] не научившись вначале объяснять ей, что n целое, т.е. не овладев паттернами, Вам вряд ли удастся!!
Предикат PrimeQ[n] спрашивает, является ли натуральное число n
простым. По идее PrimeQ[n] возврашает True, если n является простым и
False в противном случае. Однако в действительности это вероятностная команда основанная на тестах простоты. Если число не проходит хотя бы один из этих тестов, оно заведомо является составным, поэтому значе- нию False можно верить. С другой стороны, неизвестно, действительно ли число, проходящее все эти тесты, является простым. Поэтому для боль- ших чисел нельзя исключить возможность того, что PrimeQ[n] возвратит ответ True и в том случае, когда n является составным (хотя вероятность этого чрезвычайно мала!!!).
Пакет NumberTheory`PrimeQ` содержит до- полнительные функции, в частности ProvablePrimeQ[n], которая работает гораздо медленнее, чем PrimeQ[n], но зато гарантирует правильность от- вета для любого n.
Особенно важно уяснить разницу между NumberQ[x] и NumericQ[x].
Вопрос NumberQ[x] это программистский вопрос, состоящий в том, явля- ется ли x явно заданным числом, вычисления с которым производятся по численным, а не символьным алгоритмам. В то же время NumericQ[x] яв- ляется математическим вопросом, состоящим в том, принадлежит ли x
какому-то числовому множеству (в действительности, конечно, не множе- ству, а домену!) Таким образом, NumberQ[Pi] дает False — с точки зрения

244
всех используемых алгоритмов Pi представляет собой не число, а незави- симую полиномиальную переменную! В то же время NumericQ[Pi] дает
True, так как с математической точки зрения π является вещественным числом. В свою очередь MachineNumberQ[x] возвращает True, если x яв- ляется приближенным вещественным или комплексным числом машинной точности (в большинстве бытовых компьютеров, использующих систему
Windows, машинная точность 15.9546 знаков).
Предостережение.
В действительности Mathematica работает не в двузначной логике, как можно заключить из предыдущего, а в трехзначной!!! Скажем, условный оператор If имеет полный формат
If[Q,x,y,z] и работает следующим образом. Его вычисление дает
• x, если Q==True;
• y, если Q==False;
• z, если на основе имеющихся у нее сведений программа не может ре- шить, какое из равенств Q==True или Q==False имеет место.
Многие другие предикаты тоже имеют имена вида ClassQ, все эти пре- дикаты дают значение True, если аргумент относится к классу Class и
False в противном случае.
Приведем список основных содержащихся в ядре Mathematica предикатов такого вида (кроме некоторых системных предикатов, связанных с проверкой внешних форматов, MathLink и всем таким). Прежде всего, это предикаты, относящиеся к определению формы и значения выражений.
TrueQ[x]
истинность x
AtomQ[x]
x является атомом
ValueQ[x]
переменная x имеет значение
NameQ[x]
стринг "x" является именем
StringQ[x]
объект x является стрингом
OptionQ[x]
x можно рассматривать как опцию
Кроме того, имеются предикаты, относящиеся к составу стрингов.
DigitQ[x]
стринг "x" состоит только из цифр
LetterQ[x]
стринг "x" состоит только из букв
LowerCaseQ[x]
стринг "x" состоит из строчных букв
UpperCaseQ[x]
стринг "x" состоит из прописных букв
SyntaxQ[x]
стринг "x" синтаксически правилен
И, наконец, предикаты, относящиеся к определению того, является ли объ- ект списком определенного вида.
ListQ[x]
x является списком
VectorQ[x]
x является вектором
MatrixQ[x]
x является матрицей
ArrayQ[x]
x является массивом
OrderedQ[x]
список x упорядочен

245
Важный нюанс здесь состоит в том, что VectorQ, MatrixQ и ArrayQ распо- знают не только плотные, но и разреженные форматы. Сделаем несколько общих замечаний относительно имен формата BlablablaQ.
Нужно различать два близких слова, Question и Query. Question —
это вопрос, ответом на который служит True или False, в то время как
?object или ??object представляет собой запрос (на программистском жаргоне Query или Information Escape) и состоит в требовании информа- ции об определениях и/или атрибутах объекта object! Иными словами,
Query подразумевает консультацию, а не ответ в форме да/нет.
Далеко не все функции с именами такого вида являются предикатами от одного аргумента, многие из них в действительности являются отно- шениями, т.е. требуют два или три аргумента: ArgumentCountQ, FreeQ,
IntervalMemberQ, MatchQ, MemberQ, PolynomialQ, SameQ, StringMatchQ, Un- sameQ.
Далеко не все имена, заканчивающиеся на Q, являются именами пре- дикатов или отношений!!! Многие являются обычными числовыми функ- циями, в традиционные математические обозначения которых входит q.
Например, PartitionsQ дает число q(n) разбиений n на различные части,
LegendreQ — многочлен Лежандра второго рода Q
n
(x), etc., etc.
Еще несколько сотен других подобных функций определено в паке- тах. Впрочем, если Вы уже знаете, что такое кватернионы, пафос команды
QuaternionQ[z] и ее использование очевидны без дальнейших разъяснений.
Однако не все предикаты имеют такой формат, вот некоторые примеры:
x>0
Positive[x]
положительность x
x<0
Negative[x]
отрицательность x
x<=0
NonPositive[x]
неположительность x
x>=0
NonNegative[x]
неотрицательность x
Использование этих предикатов тоже совершенно понятно. Positive[x]
дает значение True в том и только том случае, когда x > 0, и False в про- тивном случае. Таким образом, Positive[x] означает ровно то же самое,
что TrueQ[x>0]. Значения остальных предикатов определяются совершен- но аналогично.

246
§ 13. Булевы функции и кванторы
Обсудим теперь булевы функции, т.е. такие функции, у которых как аргументы, так и значения принадлежат домену Booleans. Вот основные булевы функции, содержащиеся в ядре Mathematica
!x
Not[x]
отрицание x
x&&y&&z
And[x,y,z]
конъюнкция, все x, y, z имеют место x||y||y
Or[x,y,z]
дизъюнкция, хотя бы одно x, y, z имеет место
Nand[x,y,z]
хотя бы одно из x, y, z не имеет места
Nor[x,y,z]
ни одно из x, y, z не имеет места
Xor[x,y,z]
имеет место нечетное число из x, y, z
Implies[x,y]
импликация, x влечет y
Прежде всего, обратите внимание на следующий важный синтаксический момент:
Знаки & и | в сокращенном обозначении And и Or удваиваются!!! Это сделано потому, что одинарные & и | уже используются в других чрез- вычайно важных смыслах. А именно, & используется для операторного обозначения чистой функции, а | — для обозначения альтернатив в обо- значениях паттернов, подстановок, правил преобразования и т.д.
Все эти операции имеют обычный в логике и дискретной математике смысл. Операция Not выражает логическое отрицание:
In[5]:=Map[Not,
{True,False}]
Out[5]=
{False,True}
Таким образом, Not[x] в том и только том случае принимает значение True,
когда x принимает значение False. Например, Not[EvenQ[n]]===OddQ[n].
Вот таблицы истинности остальных логических функций.
In[6]:=bool=
{True,False}; bool2=Flatten[Outer[List,bool,bool],1]
Out[6]=
{{True,True},{True,False},{False,True},{False,False}};
In[7]:=Map[Apply[And,#]&,bool2]
Out[7]=
{True,False,False,False}
In[8]:=Map[Apply[Or,#]&,bool2]
Out[8]=
{True,True,True,False}
In[9]:=Map[Apply[Nand,#]&,bool2]
Out[9]=
{False,True,True,True}
In[10]:=Map[Apply[Nor,#]&,bool2]
Out[10]=
{False, False, False, True}
In[11]:=Map[Apply[Xor,#]&,bool2]
Out[11]=
{False,True,True,False}
In[12]:=Map[Apply[Implies,#]&,bool2]

247
Out[12]=
{True,False,True,True}
Обсудим несколько более тонких моментов, относящихся к употребле- нию логических связок. Для сравнения двух логических функций исполь- зуется команда LogicalExpand, вносящая все отрицания внутрь и приводя- щая аргумент к дизъюнктивной нормальной форме.
Функции Nand[x,y] и Nor[x,y] являются отрицаниями And[x,y] и
Or[x,y]. Это очевидно из определения и/или из приведенных таблиц ис- тинности, но автоматически в формы Not[And[x,y]] и Not[Or[x,y]] вы- ражения Nand[x,y] и Nor[x,y]] не конвертируются. С другой стороны,
формулы де Моргана утверждают, что
LogicalExpand[Nand[x,y]]===Or[Not[x],Not[y]],
LogicalExpand[Nor[x,y]]===And[Not[x],Not[y]].
Поэтому в дальнейшем эти связки мы можем отдельно не обсуждать.
Конечно, операции Xor и Implies тоже приводятся к нормальной фор- ме. По определению Xor[x,y] равно And[Or[x,y],Not[And[x,y]]]. Вычис- ление LogicalExpand[Xor[x,y]] дает Or[And[x,Not[y]],And[y,Not[x]]].
С другой стороны LogicalExpand[Implies[x,y]] дает Or[y,Not[x]]. Обе эти формы гораздо менее интуитивны, чем Xor[x,y] и Implies[x,y], по- этому отказываться от использования этих связок мы не будем.
Операция Not всегда вызывается с одним аргументом, а операция Im- plies — с двумя аргументами. Все остальные логические связки могут вызываться с любым количеством аргументов — или вообще без аргумен- тов. Легко видеть (тот, кто не видит, может проверить на компьютере!),
что And[] принимает значение True, Or[] и Xor[]] — значение False (на- помним, что Nand[]===Not[And[]], а Nor[]===Not[Or[]]).
ForAll[x,p]
p истинно для всех x
Exists[x,p]
p истинно для какого-то x
Resolve[p]
элиминировать кванторы в p
Resolve[p,dom]
элиминировать кванторы в p в области dom
§ 14. Реляционные операторы
Если R — какое-то отношение на некотором множестве X, например на множестве
R вещественных чисел, то функция R[x,y] проверяет, находятся ли x и y в отношении R и возвращает True, если это так и False в против- ном случае. С математической точки зрения отношение является просто предикатом от двух аргументов. Однако отличие от ранее рассмотренных предикатов состоит в том, что аргументы отношений равноправны!
x>y
Greater[x,y]
больше x>=y
GreaterEqual[x,y]
больше или равно xLess[x,y]
меньше x<=y
LessEqual[x,y]
меньше или равно

248
Вопрос x>y возвращает значение True, если система знает, что число x
больше, чем y, значение False, если система знает, что число x не больше,
чем y и, наконец, остается неэвалюированным, если система не знает, какое из этих утверждений имеет место.
Стоит подчеркнуть, что хотя мы описали эти отношения как бинарные,
все они могут вызываться с любым количеством аргументов — или даже вообще без аргументов. Кстати, какие значения истинности, по Вашему мнению, принимают Greater[] и Greater[x]? Выражение x>y>z>w или,
что то же самое, Greater[x,y,z,w] истолковывается как x>y&&y>z&&z>w.
Это значит, что, например, Less[Sqrt[2],E,Pi] принимает значение True.
Эти отношения могут фигурировать как в качестве упрощаемых вы- ражений, так и в качестве условий в командах Simplify, FullSimplify,
Refine, Assuming и т.д. Например, по умолчанию выражение
(x+y)/2>=Sqrt[x*y]
остается неэвалюированным. В то же время вычисление
In[13]:=Refine[(x+y)/2>=Sqrt[x*y],x>=0&& y>=0]
даст значение True.
Отношения x > 0, x < 0, x >= 0, x <= 0 имеют специальные названия:
Positive[x]
x положительно
Negative[x]
x отрицательно
NonPositive[x]
x неположительно
NonNegative[x]
x неотрицательно
§ 15. Числовые функции: экспонента и логарифм
В Mathematica имеется большое количество различных типов встроен- ных функций. Экспонента и логарифм относятся к так называемым чис- ловым функциям (NumericFunction), использование которых имеет ряд особенностей. Подразумевается, что эти функции принимают численные значения, в случае, когда их аргументы имеют численные значения, в чем можно убедиться при помощи вопроса NumericQ. Кроме того, к этому клас- су относятся арифметические операции, тригонометрические и обратные тригонометрические функции и несколько десятков специальных функций.
Проиллюстрируем на этих простых примерах несколько особенностей ис- пользования числовых функций:
Все эти функции имеют атрибут Listable. Иными словами, примене- ние такой функции к списку аргументов дает список значений:
In[14]:=Exp[
{0,1,Pi,0.5}]
Out[14]=
{1, e, e
π
, 1.64872
}
Во всех случаях, когда это возможно, их результат интерпретиру- ется не просто как вещественное, а как точное целое, рациональное или алгебраическое число.

249
Во всех остальных случаях их значение может быть вычислено с произ- вольной степенью точности для произвольных комплексных аргументов.
Однако (за исключением целозначных функций (таких как Floor, Ceil- ing или Round) эта точность, вообще говоря, не может быть выше той, с которой заданы аргументы.
Во всех случаях, когда это возможно, производные, неопределенные интегралы, разложения в ряды и пр. для численных функций приведены в табличном виде, в терминах других встроенных функций. Это значит,
что обращение к ним происходит практически мгновенно.
Обращение к экспоненте и логарифму происходит очевидным образом.
Exp[x]
экспонента x
Log[x]
логарифм x
Log[b,x]
логарифм x по основанию b
Проиллюстрируем на этом примере еще одно важное обстоятельство.
In[15]:=Exp[Log[x]]
Out[15]=x
In[16]:=FullSimplify[Log[Exp[x]]]
Out[16]=Log[ex]
Понятно, что здесь произошло? Экспонента от логарифма всегда равна исходному числу, а вот логарифм от экспоненты только при каких-то до- полнительных предположениях.
В языке Mathematica имеется несколь- ко функций, которые позволяют упрощать выражения при определенных предположениях такие, как Assuming и Refine и другие.
Команда Re- fine[x,y] говорит, какую форму приняло бы выражение x, если заменить в нем x на явное число, удовлетворяющее условию y. При этом условие может y состоять из любого списка или логической комбинации включе- ний, равенств и неравенств. Теперь понятно, как добиться того, чтобы
Log[Exp[x]] все же равнялось x:
In[17]:=Refine[Log[Exp[x]],Element[x,Reals]]
Out[17]=x
In[18]:=Refine[Log[Exp[x]],Element[x,Complexes]]
Out[18]=Log[ex]
Вот еще одна точно такая же ситуация, с возведением в квадрат и из- влечением квадратного корня:
In[19]:=Sqrt[x]^2
Out[19]=x
In[20]:=FullSimplify[Sqrt[x^2]]
Out[20]=

x2
In[21]:=Refine[Sqrt[x^2],Element[x,Reals]]

250
Out[21]=Abs[x]
In[22]:=Refine[Sqrt[x^2],x>=0]
Out[22]=x
§ 16. Тригонометрические и гиперболические функции
Обращение к тригонометрическим функциям вещественного или ком- плексного аргумента не представляет никакого труда, нужно только иметь в виду, что традиционные английские имена этих функций отличаются от русских, например, тангенс x обозначается tan(x), а не tg(x) котангенс —
cot(x), а не ctg(x) и т.д.
Cos[x]
косинус x
Sin[x]
синус x
Tan[x]
тангенс x
Cot[x]
котангенс x
Sec[x]
секанс x
Csc[x]
косеканс x
По умолчанию аргумент тригонометрической функции измеряется в ра- дианах. Во всех случаях, когда это возможно, значение тригонометриче- ских функций вычисляется как точное целое, рациональное или алгебра- ическое число, в остальных случах остается неэвалюированным:
In[23]:=Cos[
{0, 1, Pi/6, Pi/5, Pi/4}]
Out[23]=
{1, Cos[1],

3 2
,
1 4
(1 +

5),
1

2
}
Численные значения этих функций находится по обычным правилам для вещественных чисел:
In[24]:=N[Cos[1]]
Out[24]=0.540302
Имена основных гиперболических функций получаются добавлением бу- ковки `h' (hyperbolic) к имени соответствующей круговой функции:
Cosh[x]
гиперболический косинус x
Sinh[x]
гиперболический синус x
Tanh[x]
гиперболический тангенс x
Coth[x]
гиперболический котангенс x
Sech[x]
гиперболический секанс x
Csch[x]
гиперболический косеканс x
Имена обратных тригонометрических функций получаются из имен со-

251
ответствующих прямых функций добавлением префикса Arc:
ArcCos[x]
арккосинус x
ArcSin[x]
арксинус x
ArcTan[x]
арктангенс x
ArcCot[x]
арккотангенс x
ArcSec[x]
арксеканс x
ArcCsc[x]
арккосеканс x
Имена обратных гиперболических функций образуются совершенно анало- гично
ArcCosh[x]
гиперболический арккосинус x
ArcSinh[x]
гиперболический арксинус x
ArcTanh[x]
гиперболический арктангенс x
ArcCoth[x]
гиперболический арккотангенс x
ArcSech[x]
гиперболический арксеканс x
ArcCsch[x]
гиперболический арккосеканс x

252
МОДУЛЬ 3. Задачи
Все знание находится повсюду.
Идрис Шах, Знание как знать
I believe that mathematical reality lies outside us, and that our func- tion is to discover or observe it, and that the theorems which we prove,
and which we describe grandiloquently as our 'creations' are simply our notes of our observations.
Godfrey Harold Hardy
Mathematics is an experimental science, and definitions do not come
first, but later on.
Oliver Heavyside
In theory there is no difference between theory and practice. In prac- tice there is.
Yogi Berra

1   ...   14   15   16   17   18   19   20   21   ...   38


написать администратору сайта