Иллюстрированный самоучитель по Mathematica
Подготовка пакетов расширений системы
Mathematica
Мощным средством
расширения возможностей системы Mathematica является подготовка пакетов расширений.
Пакеты расширений позволяют создавать новые процедуры и функции и хранить
их на диске в виде файлов с расширением . m. После считывания такого пакета
с диска все входящие в него определения функций становятся доступными для использования
в соответствии с правилами, принятыми для встроенных функций. Текст пакета расширения
не выводится после его вызова, чтобы не загромождать документ вспомогательными
описаниями. В сущности, пакеты расширения — это просто наборы программ на языке
программирования системы Mathematica, подобранные по определенной тематике.
Типовая структура пакетов расширения
Структура
пакета расширений (программы) в минимальном виде выглядит следующим образом:
(* Вводный комментарий
*)
BeginPackage["Имя_пакета'
"]
Mean::usage
= "Имя функции[Параметры] Текстовый комментарий"
Begin[" 'Private' "]
Unprotected[Список_имен] Определения новых функций
End[ ]
Установка атрибутов
защиты EndPackage[ ] (* Завершающий комментарий *)
Особая структура
пакетов расширений связана с реализацией описанной выше идеологии контекстов.
Пакет открывается необязательным текстовым комментарием, который обрамляется
двойными символами « (*» и «*) ». Он может быть как
однострочным, так и многострочным. Обычно вводный комментарий включает в себя
имя пакета, наименование фирмы и автора — создателей пакета, историю развития,
дату создания и т. д. Если вы программируете для себя, можете на первых порах
опустить все эти комментарии. Но не забудьте их ввести после отладки пакета,
как того требуют культура и дисциплина программирования.
Затем пакет
открывается словом BeginPackage. Это слово дается с квадратными скобками, в
которых указывается контекст (см. выше) пакета. Обратите внимание на то, что
после имени пакета должен стоять апостроф или цепочка символов, обрамленная
апострофами. Имя пакета не должно совпадать ни с одним из известных, то есть
быть уникальным.
Эта команда
изменяет список контекстов, и он принимает вид
{Имя_пакета',System'}.
Таким образом,
на первом месте списка контекстов оказывается имя пакета, а на втором — контекст
System'. Теперь любой вводимый и не встроенный символ приобретает контекстную
приставку с именем данного пакета.
Обратите
внимание на то, что контекст System' сохранился в новом списке контекстов, но
стал вторым. Это значит, что если вы вводите слова и символы, встроенные в систему,
то они будут замещены новыми определениями. К примеру, если вы решили вычислять
функцию Sin [x] по новому и ценному для вас алгоритму, то ему будет отдаваться
предпочтение при каждом использовании этой функции до тех пор, пока вы работаете
с данным пакетом расширения. Однако, как только вы перестанете работать с пакетом,
восстановится роль встроенной функции Sin[x].
Следующий
блок пакета — сообщения о назначении функций. Эти сообщения выводятся, если
после загрузки пакета задать вопросительный знак с последующим именем функции.
Эти сообщения не обязательны, но они обеспечивают единство диалога с системой
и, безусловно, нужны при профессиональной подготовке пакета. Обычно в этих сообщениях
кратко указываются синтаксические правила использования функций и назначение
их параметров, указываемых в квадратных скобках.
Затем следует
главная часть пакета — определения новых функций. Она открывается определением
Begin [" ' Private ' "]. Оно, не меняя список контекстов,
устанавливает новый текущий контекст Имя_пакета'
Private'. Он присваивается
всем ранее не встречавшимся символам. Имя Private принято в пакетах расширения
системы Mathematica, хотя, в принципе, может быть любым другим именем. После
него следуют сами определения, в которых могут использоваться любые средства,
включенные в ядро системы.
В некоторых
случаях имена функций могут повторять ранее определенные в ядре системы. Это
полезно, если пользователь считает, что введенное им определение уже известной
функции более точно или более универсально, чем использованное в системе. В
таких случаях перед новым применением идентификатора надо позаботиться о снятии
с него защиты с помощью функции Unprotect. Именно эта часть и определяет существо
пакета и его ценность.
Завершается
эта часть определением End [ ]. При этом восстанавливается контекст, который
был до определения Begin [" ' Private' " ], то есть контекст с именем
пакета. После этого идет необязательная часть с указанием атрибутов защиты.
Пакет завершается определением EndPackage [ ], которое восстанавливает контекст,
бывший текущим до загрузки пакета (например Global'
4
), a контекст
Имя_пакета
4
помещает в начало прежнего списка контекстов..
Контексты
в системах Mathematica 3 и 4 идентичны — иначе и быть не может, поскольку
всякая старшая версия системы должна обеспечивать совместимость с предшествующей
версией. Впрочем, в Mathematica 4 включены два новых контекста, Developer
4
и Experimental
4
.
Необязательный
заключительный комментарий чаще всего дает список тестовых примеров. Он особенно
желателен, если пакет содержит определения не вполне очевидных функций. Не забывайте,
что этот комментарий не выводится и не исполняется — он нужен лишь на этапе
знакомства с пакетом. Разумеется, такое знакомство необходимо при каждой серьезной
попытке применения того или иного пакета расширения или применения системы.
В принципе,
текстовые комментарии могут вводиться на русском языке. Однако при этом возникают
определенные трудности. При выводе комментариев на экран дисплея при работе
с оболочкой системы Mathematica могут наблюдаться несоответствия между шрифтами,
установленными при вводе комментариев и при их выводе. Поэтому лучше использовать
комментарии на английском языке, тем более что комментарии ко всем встроенным
функциям и к поставляемым расширениям системы даны, естественно, на английском
языке.
Средства создания пакетов расширений
Для создания
пакетов расширений в общем случае используются следующие средства системы:
-
Begin ["context'"]
— устанавливает текущий контекст;
-
BeginPackage ["context'"]
— делает context единственным активным контекстом. Возможна также форма BeginPackage
[ "context" ", { "needl' ", "need2'",...}];'
-
Return [ ] — возвращает
Null;
-
End [ ] — возвращает
текущий контекст и переходит к предыдущему;
-
EndAdd [ ] — возвращает
текущий контекст и переходит к предыдущему, предварительно добавляя текущий
контекст к списку контекстов $Context-Path;
-
EndPackage [ ] — восстанавливает
$Context и $ContextPath в их значениях до предшествующего BeginPackage и добавляет
текущий контекст к списку $ContextPath;
-
Exit [ ] — завершает
сеанс работы Mathematica;
-
Goto [tag] —просматривает
текущее составное выражение в поиске Label [tag] и передает управление в эту
точку;
-
Interrupt [ ] — производит
прерывание в теле вычислений;
-
Label [tag] — представляет
точку в составном выражении, в которую управление передается директивой
Goto;
-
Quit [ ] — завершает
сеанс работы Mathematica.
Приведем
пример простого фрагмента программы, дающего определение новой функции ExpandBoth
с помощью некоторых из представленных средств:
(* :Title: ExpandBoth
*)
(* :Context:
ProgramminglnMathematica'ExpandBoth" *)
(* : Author:
Roman E. Maeder *)
ExpandBoth:
: usage = "ExpandBoth [e] expands all numerators and denominators in e."
Begin ["'
Private1"]
ExpandBoth [x_Plus]
:= ExpandBoth /@ x
ExpandBoth [x_]
:= Expand [ Numerator [x] ] / Expand [ Denominator [x] ]
End [ ] Null
Этот пример
настолько прост, что читателю будет нетрудно разобраться с его сутью — расширением
выражения по числителю и знаменателю. Ниже представлен сеанс работы с этим пакетом,
файл которого expboth.m размещен в каталоге
mypack, включенном в общий каталог
пакетов расширений:
<<mypack\expboth.m
?ExpandBoth
ExpandBoth [e]
expands all numerators and denominators in e.
ExpandBoth
[124 /12]
31/3
ExpandBoth
[1234/12]
617/6
Мы вернемся
к рассмотрению построения пакетов расширений после более детального рассмотрения
некоторых деталей этого процесса.
Текстовые сообщения и комментарии
Ценность
многих программ на любом языке программирования нередко сводится к нулю из-за
отсутствия подробных текстовых комментариев. Из-за этого даже сами разработчики
программ через месяц-другой перестают понимать собственные творения. А что говорить
о пользователях, рискующих применить такие программы?
Для создания
текстовых комментариев различного назначения (как выводимых, так и не выводимых
на экран в ходе работы с пакетом) в языке программирования системы Mathematica
используются следующие средства:
-
(* Comment *) — задание
не выводимого на экран текстового комментария, как однострочного, так и многострочного,
в любом месте пакета;
-
Message [symbol: :
tag] — вывод сообщения symbol::tag, если только вывод сообщений не отключен;
-
Message [symbol: :tag,
e1, e2,...] — выводит сообщение, вставляя значения ei по мере необходимости;
-
$MessageList — глобальная
переменная, возвращающая список имен сообщений, вырабатываемых во время вычисления
текущей входной строки. Имя каждого сообщения заключено в HoldForm [ ]. $MessageList
сохраняется в MessageList [n] и переустанавливается в { } после того, как
произведена п-я выходная строка;
-
MessageList [n] —
глобальный объект, который является списком имен (сообщений), которые вырабатываются
в процессе обработки п-й входной строки;
-
MessageName, применяется
в виде symbol: : tag или MessageName [symbol, "tag" ] — имя для
сообщения;
-
$MessagePrePrint —
глобальная переменная, чье значение, если установлено, применяется к выражениям
перед тем, как они помещаются в текст сообщений;
-
$Messages — возвращает
список файлов и каналов, в которые направляется вывод сообщений;
-
Messages [symbol] —
возвращает все сообщения, присвоенные данному символу
symbol.
Следует отметить,
что широкое применение комментариев обычно является признаком культуры программирования.
Это особенно важно для математических систем, реализующих вычисления по сложным
и подчас малопонятным для неспециалистов алгоритмам. Без подробных комментариев
пакеты расширений и применений теряют свою практическую полезность и превращаются
в ребусы — увы, куда менее интересные, чем те, которые публикуются в газетах
и журналах.
Защита идентификаторов от модификации
Атрибут
защиты Protected
Как уже отмечалось,
система Mathematica позволяет вводить константы, переменные и функции со своими
именами — идентификаторами. Между функциями можно задавать различные отношения,
в том числе и те, которые не соответствуют правилам, заданным в ядре системы.
Идентификаторы
должны быть уникальными, то есть не совпадать с именами встроенных функций,
директив, опций, переменных и констант. Однако как быть, если нужно задать новое
отношение для уже имеющихся встроенных функций или изменить их определения?
Для решения
таких вопросов в систему введена защита идентификаторов от модификации,
которая при необходимости может сниматься. Все встроенные в
ядро
именованные объекты языка программирования системы являются защищенными по умолчанию.
Они имеют соответствующий признак — атрибут Protected (защищенный).
Установка
и снятие атрибута защиты
Для управления
средствами защиты от модификации используются следующие директивы:
-
Protect [s1, s2,...]
— устанавливает атрибут защиты от модификации
(Protected) для перечисленных
символов si;
-
Protect [\"forml\",
\"form2\",...] — устанавливает атрибут защиты от модификации для
всех символов, имена которых сопоставимы с любым из указанных строковых шаблонов
f ormi;
-
Unprotect [s1, s2,...]
— удаляет атрибут защиты от модификации (Protected) для символов
si, что делает
возможной их модификацию;
-
Unprotect [\"forml\",
\"form2\",...] — снимает защиту всех символов, имена которых текстуально
(по буквам) сопоставимы с любым из указанных
formi.
Дополнительные
функции защиты
Следующие
атрибуты и директивы также используются при управлении модификацией:
-
NProtectedAll — атрибут,
устанавливающий, что ни один из аргументов функции не будет модифицирован
при применении N [ ];
-
NProtectedFirst —
атрибут, указывающий, что первый аргумент функции не будет модифицирован применением
N [ ];
-
NProtectedRest — атрибут,
устанавливающий, что все аргументы после первого аргумента функции не будут
модифицированы применением N [ ].
Мы уже рассматривали
модификацию функций, в частности снятие и назначение атрибутов защиты. Отметим
лишь, что из последующих примеров будет ясно, что эти операции широко применяются
в пакетах расширений.
Примеры подготовки пакетов расширений
Наиболее
сложным моментом работы с системой Mathematica является разработка пакетов расширения
профессионального качества. Именно такие пакеты позволяют приспособить всю мощь
системы к решению тех задач, которые полезны конкретному пользователю.
Начать работу
с системой можно за несколько часов. Реальное ее освоение потребует нескольких
месяцев упорной работы. А подготовка серьезных пакетов, решающих достаточно
сложные задачи, может занять и несколько лет. Для облегчения этого процесса
рассмотрим основные приемы подготовки пакетов расширений. Напоминаем, что пакеты
можно готовить как в оболочке системы (их затем
следует записать на диск как файлы с расширением .т), так и с помощью .внешних
текстовых редакторов.
В этом разделе
представлено несколько примеров построения пакетов расширений системы Mathematica
(версии не ниже 3.0), взятых из книги [34], а точнее, из примеров этой книги,
включенных в справочную базу данных систем
Mathematica. Из примеров удалена
большая часть текстовых комментариев, сделанных на английском языке.
Пакет
проверки выражений на их алгебраичность
Следующий
пакет содержит определение функции AlgExpQ [expr], которая позволяет выяснить,
является ли выражение ехрг алгебраическим.
(* :Title: AlgExp *)
(* :Context: Pro
gra
mminglnMathematica4AlgExp4
*) BeginPackage["ProgramminglnMathematica
' AlgExp '"]
AlgExpQ::usage
= "AlgExpQ[expr] returns true if expr is an algebraic expression."
Begin["'Privateч"]
SetAttributes[AlgExpQ, bistable]
AlgExpQ[ _Integer
] = True
AlgExpQ[ _Rational
] = True
AlgExpQ[ c_Complex
] := AlgExpQ[Re[c]] && AlgExpQ[Im[c]]
AlgExpQ[ _Symbol
] = True
AlgExpQ[ a_
+ b_ ] := AlgExpQ[a] && AlgExpQ[b]
AlgExpQ[ a_
* b_ ] := AlgExpQ[a] && AlgExpQ[b]
AlgExpQ[ a_
^ b_Integer ] := AlgExpQ[a]
AlgExpQ[ a_
^ b_Rational ] := AlgExpQ[a]
AlgExpQ[_] =
False End[]
EndPackage[]
Если выражение
является алгебраическим, то функция AlgExpQ возвращает логическое значение
True,
иначе она возвращает значение False:
<<mypack\algexp.m
? AlgExpQ
AlgExpQ[expr]
returns true
if expr is an
algebraic expression.
AlgExpQ [a
* x ^ 2 + b * x + c]
True
AlgExpQ[Sqrt[x]]
True
AlgExpQ["x^2+l"]
False
AlgExpQ[1]
True AlgExpQ[1.0]
False
Пакет
реализации метода Рунге—Кутта
Теперь рассмотрим,
как выглядит пакет расширения, решающий систему дифференциальных уравнений хорошо
известным численным методом Рунге—Кутта четвертого порядка. Ниже представлена
распечатка данного пакета.
(* :Title: RungeKutta
*)
(* iContext:
ProgramminglnMathematica'RungeKutta' *)
BeginPackage["ProgramminglnMathematica'RungeKutta'"]
RKSolve::usage
=
"RKSolve[{el,e2,..},
{yl,y2,..}, {al,a2,..}, {tl, dt}] numerically integrates the ei as functions
of the yi with inital values ai.The integration proceeds in steps of dt from
0 to tl.
RKSolve[{el,
e2,..},{yl,y2,..},{al,a2,..},{t,t0,tl, dt} ] integrates a time-dependent system
from t0 to tl."
Begin["'Private'"]
RKStep[f_, y_,
y0_, dt_] :=
Module [{ kl,
k2, k3, k4 }, kl = dt N[ f /. Thread[y -> yO] ];
k2 = dt N[ f
/. Thread[y -> y0 + kl/2] ];
k3 = dt N[ f
/. Thread [y -> yO + k2/2] ] ;
k4 = dt N[ f
/. Thread [y -> yO + k3] ] ;
y0 + (kl + 2
k2 + 2 k3 + k4)/6
RKSolve[f_List,
y_List, y0_List, {tl_, dt_}] :=
NestList[ RKStepff,
y, #, N[dt]]&, N[y0], Round [N [ tl /dt ]] ] /;
Length [f] ==
Length [y] == Length [y0]
RKSolve [f_List,
y_List, y0_List, {t_, t0_, tl_, dt_}] := Module f { res } ,
res = RKSolve
[ Append[f, 1], Append[y, t] , Append[y0, t0], {tl-t0, dt} ] ;
Drop[#, -1]&
/@ res /;
Length [f] ==
Length [y] == Length [y0]
End[]
Protect [ RKSolve
]
EndPackage[]
Знающие реализацию
этого метода обратят внимание на естественность записи общеизвестных математических
операций. Пакет содержит определения двух функций: основной
(RKSolve) и вспомогательной (RKStep). Последняя содержит вычисление решения на очередном шаге алгоритма
по результатам вычислений на предшествующем шаге. Используется подстановка для
переменной х и вычисление решения на очередном шаге по известной формуле Рунге—
Кутта четвертого порядка точности.
Теперь рассмотрим,
как можно использовать такой пакет, создать который можно в любом текстовом
редакторе, например в редакторе NotePad, входящем в состав Windows 95/98. Для
удобства работы можно поместить файл этого пакета rk4.m в папку
Mypack, расположенную
в папке со стандартными пакетами. В этом случае вызов пакета и проверка его
загрузки осуществляются следующим образом:
<< mypack\rk4.m
?RKSolve
RKSolve [ {el,
e2, ..}, {yl,y2,..}, {al,a2,..}, {tl, dt}] numerically integrates the ei as
functions of the yi with inital values ai.The integration proceeds in steps
of dt from 0 to tl. RKSolve [ {el, e2, ..}, {yl,y2,..}, {al,a2,..}, {t, t0,
tl, dt}] integrates a time-dependent system from t0 to tl .
Итак, при
обращении ?RKSolve выводится информация о формате применения функции
RKSolve.
Она задана на английском языке. Можно записать эту информации и на русском языке,
однако при этом возможна нестыковка наборов шрифтов. Поэтому рекомендуется подобную
информацию давать на английском языке. В нашем случае решается система дифференциальных
уравнений первого порядка в форме Коши, заданная правыми частями
{el, е2,...}
с переменными {yl, у2,...} и их начальными значениями
{al, а2,...} в интервале
времени от 0 до .1 при фиксированном шаге dt. Во второй форме записи функции
время t может меняться от tO до tl с шагом dt.
Приведенный
ниже пример демонстрирует, как этот пакет используется на практике для решения
системы дифференциальных уравнений y' = t*y + z и z' = t + y*z
при начальных
значениях у = z = 1 и t, меняющемся от 1 до 1.5 с шагом 0.1:
RKSolve[{t*y
+ z, t + y*z}, {у, z}, {1, 1}, {t, 1, 1.5, 0.1}]
{{!., 1.}, {1.22754,
1.22844), {1.52241, 1.53202),
{1.90912, 1.95373},
{2.42456, 2.57444), {3.12741, 3.55937}}
Решение представлено
списком значений {yi, zi}, определяющим зависимости y(t)
и z(t). Этот
пример хорошо иллюстрирует реализацию популярного численного метода для решения
систем дифференциальных уравнений.
Пакет
символьных преобразований тригонометрических функций
Следующий
пакет служит для демонстрации символьных преобразований тригонометрических функций
синуса и косинуса.
(* :Title: TrigDefine
*)
(* :Context:
ProgramminglnMathematica'TrigDefine" *)
BeginPackage["ProgramminglnMathematica'
TrigDefine'"]
TrigDefine::usage
= "TrigDefine.m defines global rules for putting products of trigonometric
functions into normal form."
Begin["'Private'"]
(* set the private context *)
(* unprotect
any system functions for which rules will be defined *)
protected =
Unprotect[ Sin, Cos ] (* linearization *) Sin/: Sin[x_] Cos[y_] := Sin[x+y]/2
+ Sin[x-y]/2
Sin/: Sin[x_]
Sin[y_] := Cos[x-y]/2 - Cos[x+y]/2 Cos/: Cos[x_] Cos[y_] := Cos[x+y]/2 + Cos[x-y]/2
Sin/: Sin[x_]An_Integer?Positive
:=
Expandt (1/2- Cos[2x]/2) Sin [x]^(n-2) ]
Cos/: Cos[x_]An_Integer?Positive
:=
Expand[(l/2
+ Cos[2x]/2) Cos[x]^(n-2)]
Protect[ Evaluate[protected]](*
restore protection of system symbols *)
End[] (* end
the private context *) EndPackage[] (* end the package context *)
Данный пакет
задает преобразования для произведений sin(x)
cos(x), sin(x) sin(y) и cos(x) cos(y), а также для sin(x)
n
и
cos(x)
n
. Следующие
примеры наглядно показывают работу с этим пакетом:
<<
mypack\trigdefine.m
?Sin
Sin[z] gives
the sine of z. Sin[a]*Cos[b]
1/2Sin[a-b]
+ 1/2 Sin[a+b]
Sin[a]*Sin[b]
1/2Cos[a-b]
- 1/2Cos[a+b]
Cos[a]*Cos[b]
1/2 Costa-b]
+ 1/2Cos[a+b]
Sin[x]^2
1/2-1/2 Cos[2x]
Cos[x]^3
Sec[x]/4 +1/2Cos[2x]
Sec[x] + 1/4(1/2 + 1/2 Cos[4x]) Sec[x]
Sin[x]^n
Sin[x]n
Данный пример
— наглядная иллюстрация программирования символьных вычислений.
Пакет
вычисления функций комплексного переменного
Еще один
пакет расширений для вычисления функций комплексного переменного (блок пакетов
ALGEBRA) представлен распечаткой, приведенной ниже.
(* :Title: Relm
*)
(* :Authors:
Roman Maeder and Martin Buchholz *) BeginPackage [ "Algebra 'RelrrT "]
RealValued::usage
= "RealValued[f] declares f to be a real-valued function
(for real-valued
arguments)."
SBegin["'Private'"]
protected =
Unprotect[Re, Im, Abs, Conjugate, Arg] (* test for "reality", excluding
numbers *)
realQ[x_] /;
!NumberQ[x] := Im[x] == 0 imagQ[x_] /; !NumberQ[x] := Re[x] == 0
(* fundamental
rules *)
Re[x_] := x
/; realQ[x] Arg[x_] := 0 /; Positive[x] Arg[x_J :=Pi /; Negative[x] Conjugate[x_]
:= x /; realQ[x] Conjugate[x_] := -x /; imagQ[x]
(* there must
not be a rule for Im[x] in terms of Re[x] !! *) (* things known to be real *)
Im[Re[_]] :=
0 Im[Im[_]] := 0 Im[Abs[_]] := 0 Im[Arg[_]] := 0 Im[x_?Positive] = 0 Im[x_?Negative]
= 0
Im[x_ ^ y_]
:= 0,/; Positive[x] && Im[y] == 0 Im[Log[r ?Positive]] := 0
(*' arithmetic
*)
Re[x_Plus] :=
Re /@ x Im[x_Plus] := Im /@ x
Re[x_ y_Plus]
:= Re[Expand[x y]] Im[x_ y_Plus] := Im[Expand[x y]]
Re[x_ y_] :=
Re[x] Re[y]— Im[x] Im[y] Im[x_ y_] := Re[x] Im[y] + Im[x] Re[y]
(* products *)
Re[(x_?Positive y_) ^k_] := Re[x^k y^k]
Im[(x_?Positive y_)^k_]
:= Im[x^k yAk]
(* nested powers
*)
Re[(x_?Positive ^ y_ /; Im[x]==0)^k_] :=
Re[x^(y k)] Im[(x_?Positive ^ y_ /; Im[x]==0)"kj := Im[хл(у k)]
Re[ l/x_ ] :=
Re[x] / (Re[x]^2 + Im[х]^2) Im[ l/x_ ] := -Im[x] / (Re[x]"2
+ Im[x]A2)
Im[x_^2] :=
2 Re[x] Im[x]
Re[ x_^n_Integer
] := Block[{a, b},
a = Round[n/2];
b = n-a;
Re[x^a] Re[x^b] - Im[х^а] 1т[х^b] ]
Im[ x_^n_Integer
] :=Block[{a, b}, a = Round[n/2]; b = n-a; Re[x^a] Im[х^b]
+ Im[х^a] Re[x^b] ]
Re[x_IntegerAn_Rational]
:= 0 /; IntegerQ[2n] && Negative[x]
Im[x_IntegerAn_Rational]
:=
(-х)лп
(-1)л((Numerator[n]-l)/2 /; IntegerQ[2n] && Negative[x]
(* functions
*)
Re[Log[r_?Negative]]
:= Log[-r] Im[Log[r_?Negative]] := Pi Re[Log[z_]] := Log[Abs[z]] /; realQ[z]
Re[Log[z_]] := (1/2) Log[Re[z]^2 + Im[z]^2] Im[Log[z_]]
:= Arg[z]
Re[Log[a_ b_]]
:= Re[Log[a] + Log[b]]
Im[Log[a_ b_]]
:= Im[Log[a] + Log[b]]
Re[Log[a_^c_]]
:= Re[c Log[a]]
Im[Log[a_^c_]]
:= Im[c Log[a]]
Ке[Е^х_] :=Cos[Im[x]] Exp[Re[x]]
Im[Е^х_] := Sin[Im[x]] Exp[Re[x]]
Re[Sin[x_]]
:= Sin[Re[x]] Cosh[Im[x]] Im[Sin[x_]] :=Cos[Re[x]] Sinh[Im[x]]
Re[Cos[x_]]
:= Cos[Re[x]] Cosh[Im[x]] Im[Cos[x_]] := -Sin[Re[x]] Sinh[Im[x]]
Re[Sinh[x_]]
:= Sinh[Re[x]] Cos[Im[x]] Im[Sinh[x_J] := Cosh[Re[x]] Sin[Im[x]]
Re[Cosh[x_]]
:= Cosh[Re[x]] Cos[Im[x]] Im[Cosh[x_]] := Sinh[Re[x]] Sin[Im[x]]
(* conjugates
*)
Re[Conjugate[z_]]
:= Re[z] Im[Conjugate[z_]] :=
Conjugate[x_Plus]:=
Conjugate /@ x Conjugate[x_Times]:= Conjugate /@ x Conjugate[x_^n_Integer]:=
Conjugate[x]An Conjugate[Conjugate[x_]]:= x
(* real-valued
rules *)
Attributes[RealValued]
= {Listable, HoldAll} Attributes[RealValuedQ] = {HoldFirst}
RealValued[f_Symbol]
:= (f/: RealValuedQ[f] = True; f) RealValued[f ] := RealValued /@ {f}
Im[ (_?RealValuedQ)
[_? (Im[#J ==0&)...] ] := 0
(* define built-in
function to be real-valued *)
DoRules[flist_]
:= Block[{protected},
protected =
Unprotect[flist];
RealValued[flist];
Protect[Evaluate[protected]]
]
DoRules[{Sin,
Cos, Tan, ArcSin, ArcCos, ArcTan, ArcCot, Sinh, Cosh, Tanh, ArcSinh, ArcCosh,
ArcTanh, Floor, Ceiling, Round, Sign, Factorial}]
Protect[Evaluate[protected]]
End[]
Protect[RealValued]
EndPackage[]
Как нетрудно
заметить, в этом пакете задано вычисление действительной и мнимой частей для
ряда тригонометрических, гиперболических и числовых функций.
Пакет
расширения графики
Следующий
пример иллюстрирует подготовку графического пакета расширения, который строит
графики ряда функций с автоматической установкой стиля линий каждой кривой.
(* :Title: Plot
*)
(* :Context:
ProgramminglnMathematica"Plot" *)
BeginPackage["ProgramminglnMathematica4
Plot4"]
Plot::usage
= Plot::usage <> " If several functions are plotted, different plot
styles are chosen automatically."
Begin["'Private'"]
protected = Unprotect[Plot]
$PlotActive
= True
Plot[f_List,
args__]/; $PlotActive := Block[{$PlotActive = False},
With[{styles
= NestList[nextStyle, firstStyle, Length[Unevaluated[f]]-1]}, Plot[f, args,
PlotStyle -> styles] ] ]
(* style definitions
*)
unit = 1/100
max = 5
firstStyle =
Dashing[{}]
nextStyle[Dashing[{alpha__,
x_, y_, omega__}]] /; x > у + unit :=
Dashing[{alpha,
x, у + unit, omega}] nextStyle[Dashing[l_List]] :=
Dashing[Prepend[Table[unit,
{Length[1] +1}], max unit]]
Protect! Evaluate[protected]
]
End[]
EndPackage[]
Рисунок 10.6
показывает применение данного пакета.
Пакеты-пустышки
Разумеется,
эти примеры не исчерпывают всего разнообразия пакетов расширений. В сущности,
они не дают ничего нового, поскольку приведенные листинги являются просто упрощением
гораздо более полных и мощных пакетов, уже входящих в систему. В Mathematica
3 и 4 многие функции из пакетов расширения перекочевали в ядро системы, что
позволило существенно ускорить вычисления. Поэтому в пакетах расширения можно
встретить определения-пустышки, просто сообщающие об этом и не содержащие новых
определений функций. Примером такого рода является модуль
countroot.m, листинг
которого приведен ниже.
Рис.
10.6.
Пример применения функции Plot из пакета расширения plot.m
(* :Name: Algebra"CountRoots' *)
(* :Copyright:
Copyright 1994-1996, Wolfram Research, Inc.*)
(* :Summary:All
CountRoots functionality is now provided by Algebra'Rootlsolation". The
package Algebra'CountRoots" is obsolete.
*)
Needs["Algebraч
Rootlsolation'" ]
CountRoots::obslt
=
"All CountRoots
functionality is now provided by
Algebra'Rootlsolation'.
The package
Algebra'CountRoots" is obsolete."
Message[CountRoots::obslt]
Надо прямо
сказать, что в области математики пользователь средней квалификации едва ли
может придумать что-либо такое, что еще не включено в ядро или в пакеты расширений
системы. Разумно готовить такие пакеты лишь для тех специальных областей применения
математики, с которыми работает пользователь, — например в области физики, химии,
механики, электротехники и радиотехники и т. д. Однако более вероятно, что пользователь
предпочтет готовить не пакеты расширений, а пакеты применений.
Пакеты
применений — это группы документов с программами, предназначенные для решения
определенного класса математических или научно-технических проблем и задач.
В отличие от пакетов расширения, в документах пакетов применений обычно дается
подробно комментируемое описание всех основных алгоритмов решения задач. При
этом комментарий, как правило, выводится на экран дисплея.
Довольно
часто в пакетах применений используется прием объединения ряда ячеек в одну
с общим текстовым заголовком. Это особенно полезно для организации вспомогательных
и промежуточных вычислений, ячейки которых загромождают экран и лишают текст
документа наглядности. Данный прием скрывает такие вычисления, но позволяет
в любой момент вывести их на экран дисплея при активизации маленького прямоугольника,
отмечающего такие совмещенные ячейки. Тексты документов, поставляемых с системой,
являются прекрасными образцами использования этого приема.
Документы
пакетов применения — это конечный продукт практического использования системы
Mathematica. Поэтому они могут включать в себя все ранее описанные средства
системы. Как уже неоднократно отмечалось, документы записываются на диск в виде
файлов с расширением .т (в ранних версиях Mathematica — .та), а их полный битовый
образ (включающий рисунки) сохраняется во вспомогательных файлах с расширением
.mb. При большом числе сложных рисунков в документе эти файлы могут быть весьма
большими — сотни килобайт и даже единицы мегабайт.