@c Language=Russian
@c Encoding=CP1251
@c File=Rules.texi 
@c OriginalRevision=1.35
@c TranslatedBy: (c) 2007-09-11 Valery Pipin <pip@iszf.irk.ru>


@menu
* Введение в правила преобразований и шаблоны::  
* Функции и переменные для правил преобразования и шаблонов::  
@end menu

@node Введение в правила преобразований и шаблоны, Функции и переменные для правил преобразования и шаблонов, Правила преобразования и шаблоны, Правила преобразования и шаблоны
@section Введение в правила преобразований и шаблоны

Данный раздел описывает особенности программирования правил
преобразований и шаблонов, применяемые в Maxima для упрощения выражений.
Имеется две группы функций, реализующих несколько различающиеся схемы применения
шаблонов преобразований.
К одной группе относятся функции @code{tellsimp}, @code{tellsimpafter}, 
@code{defmatch}, @code{defrule},@code{apply1}, @code{applyb1} и @code{apply2}.
В другую группу входят функции @code{let} и @code{letsimp}.
В обоих группах шаблоны определяются через переменные
шаблонов, объявляемые функцией @code{matchdeclare}.

Правила преобразований, определенные в процедурах @code{tellsimp} и
@code{tellsimpafter}, применяются Maxima автоматически (если
управляющая переменная @code{simp} имеет значение @code{true}).
Правила преобразований, определенные в процедурах @code{defmatch},
@code{defrule} и @code{let} применяются только при явном вызове
соответствующих функций.

Имеются, также, дополнительные возможности использования правил
преобразований, например, при
работе с полиномами в процедуре @code{tellrat}, и для коммутативной и
некоммутативной алгебры в пакете  @code{affine}.  

@opencatbox
@category{Упрощение} @category{Правила преобразования и шаблоны}
@closecatbox

@c end concepts Rules and Patterns
@node Функции и переменные для правил преобразования и шаблонов,  , Введение в правила преобразований и шаблоны, Правила преобразования и шаблоны
@section Функции и переменные для правил преобразования и шаблонов

@c NEEDS CLARIFICATION AND EXAMPLES
@deffn {Функция} apply1 (@var{expr}, @var{rule_1}, ..., @var{rule_n})
Осуществляет повторное применение правила преобразования @var{rule_1} к
@var{expr} до тех пор пока выражение отвечает шаблону преобразования,
затем, таким же образом осуществляется повторное применение этого правила ко всем
подвыражениям @var{expr}, слева направо. 
Далее, к полученному
результату тем же способом применяется правило @var{rule_2} и так далее 
все последующие правила вплоть до @var{rule_n}. Конечный результат возвращается.

Переменная @code{maxapplydepth} контролирует нижнюю глубину уровня подвыражения до
которого применяются правила преобразований в функциях @code{apply1} и @code{apply2}.

См. также @var{applyb1}, @code{apply2} и @code{let}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@c NEEDS CLARIFICATION AND EXAMPLES
@deffn {Функция} apply2 (@var{expr}, @var{rule_1}, ..., @var{rule_n})
Если правило @var{rule_1} неприменимо на подвыражении  @var{expr},
тогда применяется правило @var{rule_2} и далее по той же схеме остальные
правила. Только если каждое из правил является неприменимым на данном подвыражении @var{expr}, 
программа переходит на следующий уровень подвыражнния @var{expr}, 
и по той же схеме последовательно применяет весь набор правил, 
начиная с первого. Если применение одного из правил оказывается
успешным, тогда весь набор правил заново применяется к
этому подвыражению.

Переменная @code{maxapplydepth} контролирует нижнюю глубину уровня подвыражения до
которого применяются правила преобразований в функциях @code{apply1} и @code{apply2}.

См. также @code{apply1} и @code{let}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@c NEEDS CLARIFICATION AND EXAMPLES
@deffn {Функция} applyb1 (@var{expr}, @var{rule_1}, ..., @var{rule_n})
В отличие от @code{apply1} применяется по восходящей, т.е., сначала на
самом глубоком уровне @var{expr} повторяется применение правила
@var{rule_1}. Затем программа переходит на более высокие уровни
@var{expr} и применяет данное правило по той же схеме.  После того как
применение правила @var{rule_1} терпит неудачу на самом вернем уровне
@var{expr} программа переходит к применению правила  @var{rule_2} по
той же схеме (по восходящей) и так далее, заканчивая применением
правила  @var{rule_n}. После этого возвращается результат.

Функция @code{applyb1} аналогична @code{apply1}, но работает по восходящей.

Переменная @code{maxapplyheight} контролирует высоту уровня подвыражения до
которого применяются правила преобразований в функции @code{applyb1}.

См. также @code{apply1}, @code{apply2} и @code{let}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@defvr {Управляющая переменная} current_let_rule_package
Значение по умолчанию: @code{default_let_rule_package}

@code{current_let_rule_package} - имя пакета правил, которые, если не
определен другой пакет правил, используются функциями из программы  @code{let} (такими как,
@code{letsimp}, и т.д.) @c NEED TO GIVE AN EXPLICIT LIST HERE (NOT "ETC")
Эта переменной может быть присвоено имя любого пакета правил 
преобразований, определенного при помощи функции @code{let}.

При вызове @code{letsimp (expr, rule_pkg_name)},
пакет правил @code{rule_pkg_name} используется только во время данного
действия, при этом  значение переменной @code{current_let_rule_package}
остается неизменным.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end defvr

@defvr {Управляющая переменная} default_let_rule_package
@c DEFAULT BINDING OF default_let_rule_package IS default_let_rule_package (BOUND TO ITSELF)
Значение по умолчанию: @code{default_let_rule_package}

@c THIS IS SORT OF CONFUSING. PROBABLY NEED TO GIVE MORE DETAIL HERE
@code{default_let_rule_package} - имя пакета правил, используемого по умолчанию, если
пакет правил не был задан в явном виде при вызове @code{let} или через
изменение значения переменной @code{current_let_rule_package}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end defvr

@deffn {Функция} defmatch (@var{progname}, @var{pattern}, @var{x_1}, ..., @var{x_n})
@deffnx {Функция} defmatch (@var{progname}, @var{pattern})
Определяет функцию @code{@var{progname} (@var{expr}, @var{x_1}, ..., @var{x_n})}, 
которая проверяет выражение @var{expr} на соответствие шаблону @var{pattern}.

Шаблон @var{pattern} - выражение, содержащее аргументы шаблона @var{x_1}, ..., @var{x_n} (если есть)
и переменные шаблона (если есть).
Аргументы шаблона задаются в явном виде, как аргументы функции
@code{defmatch}, а переменные шаблона декларируются функцией @code{matchdeclare}.
Всякая переменная, не декларированная как переменная шаблона при помощи @code{mathdeclare}
или как аргумент шаблона при помощи @code{defmatch} соответствует только сама себе.

Первым аргументом создаваемой функции @var{progname} является выражение,
проверяемое на соответствие шаблону, а другие аргументы это
актуальные параметры, соответствующие аргументам шаблона  @var{x_1}, ..., @var{x_n}.

Если проверка на соответствие шаблону оказывается успешной, то
@var{progname} возвращает список уравнений, в которых левые части
являются аргументами и переменными шаблона, а правые части - подвыражения @var{expr},
сопоставленные данным аргументам и переменным. 
Переменным шаблона, но не аргументам шаблона, присваиваются соответствующие значения.
В случае неудачи сопоставления @var{progname} возвращает @code{false}.  

Любая переменная, не объявленная в параметрах шаблона в
@code{matchdeclare} или в переменных шаблона в @code{defmatch},
сопоставляется только самой себе.

Программа для буквального шаблона, т.е. шаблона не содержащего ни аргументов ни переменных, 
в случае удачи сопоставления возвращает @code{true}.

См. также @code{matchdeclare}, @code{defrule}, @code{tellsimp} и @code{tellsimpafter}.

Примеры:

Определим функцию @code{linearp (expr, x)}, которая проверяет может ли @code{expr}  быть представлено
ввиде @code{a*x + b}, где @code{a} и @code{b} не содержат @code{x} и @code{a} отлично от нуля.
Эта функция сопоставима с выражениями линейными по любой переменной,
поскольку аргумент шаблона @code{x} определен в @code{defmatch}.
@c HOW HARD WILL MAXIMA TRY TO COLLECT TERMS AND DO OTHER MUNGEING TO FIT THE PATTERN ??

@c ===beg===
@c matchdeclare (a, lambda ([e], e#0 and freeof(x, e)), b, 
@c                     freeof(x));
@c defmatch (linearp, a*x + b, x);
@c linearp (3*z + (y + 1)*z + y^2, z);
@c a;
@c b;
@c x;
@c ===end===
@example
(%i1) matchdeclare (a, lambda ([e], e#0 and freeof(x, e)), b,
                    freeof(x));
(%o1)                         done
(%i2) defmatch (linearp, a*x + b, x);
(%o2)                        linearp
(%i3) linearp (3*z + (y + 1)*z + y^2, z);
                         2
(%o3)              [b = y , a = y + 4, x = z]
(%i4) a;
(%o4)                         y + 4
(%i5) b;
                                2
(%o5)                          y
(%i6) x;
(%o6)                           x
@end example

Определим функцию @code{linearp(expr)}, которая проверяет может ли @code{expr} быть представлено
ввиде @code{a*x + b}, где @code{a} и @code{b} не содержат @code{x} и @code{a} отлично от нуля.
Эта функция сопоставима с выражениями линейными только по @code{x},
поскольку в @code{defmatch} не заданы никакие аргументы шаблона.

@c ===beg===
@c matchdeclare (a, lambda ([e], e#0 and freeof(x, e)), b, 
@c                     freeof(x));
@c defmatch (linearp, a*x + b);
@c linearp (3*z + (y + 1)*z + y^2);
@c linearp (3*x + (y + 1)*x + y^2);
@c ===end===
@example
(%i1) matchdeclare (a, lambda ([e], e#0 and freeof(x, e)), b,
                    freeof(x));
(%o1)                         done
(%i2) defmatch (linearp, a*x + b);
(%o2)                        linearp
(%i3) linearp (3*z + (y + 1)*z + y^2);
(%o3)                         false
(%i4) linearp (3*x + (y + 1)*x + y^2);
                             2
(%o4)                  [b = y , a = y + 4]
@end example

Определим функцию @code{checklimits(expr)}, которая проверяет,
определяет ли @code{expr} интеграл.

@c ===beg===
@c matchdeclare ([a, f], true);
@c constinterval (l, h) := constantp (h - l);
@c matchdeclare (b, constinterval (a));
@c matchdeclare (x, atom);
@c simp : false;
@c defmatch (checklimits, 'integrate (f, x, a, b));
@c simp : true;
@c 'integrate (sin(t), t, %pi + x, 2*%pi + x);
@c checklimits (%);
@c ===end===
@example
(%i1) matchdeclare ([a, f], true);
(%o1)                         done
(%i2) constinterval (l, h) := constantp (h - l);
(%o2)        constinterval(l, h) := constantp(h - l)
(%i3) matchdeclare (b, constinterval (a));
(%o3)                         done
(%i4) matchdeclare (x, atom);
(%o4)                         done
(%i5) simp : false;
(%o5)                         false
(%i6) defmatch (checklimits, 'integrate (f, x, a, b));
(%o6)                      checklimits
(%i7) simp : true;
(%o7)                         true
(%i8) 'integrate (sin(t), t, %pi + x, 2*%pi + x);
                       x + 2 %pi
                      /
                      [
(%o8)                 I          sin(t) dt
                      ]
                      /
                       x + %pi
(%i9) checklimits (%);
(%o9)    [b = x + 2 %pi, a = x + %pi, x = t, f = sin(t)]
@end example

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@c NEEDS CLARIFICATION AND EXAMPLES
@deffn {Функция} defrule (@var{rulename}, @var{pattern}, @var{replacement})
Определяет и именует правило преобразования для данного шаблона.
Если правило c именем @var{rulename} применяется к выражению
(путем @code{apply1}, @code{applyb1} или @code{apply2}), то каждое
подвыражение, удовлетворяющее шаблону, заменяется соответствующей подстановкой. 
После этого выражение упрощается.

Правила могут рассматриваться как функции, преобразующие выражение путем
одной операции сопоставления с шаблоном и подстановки. 
При неудаче сопоставления, функция правила преобразования возвращает @code{false}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@c NEEDS EXAMPLES
@deffn {Функция} disprule (@var{rulename_1}, ..., @var{rulename_2})
@deffnx {Функция} disprule (all)
Выводит правила преобразований и их имена @var{rulename_1}, ..., @var{rulename_n},
определенные в  @code{defrule}, @code{tellsimp} или @code{tellsimpafter}, или
шаблоны, определенные @code{defmatch}.
Каждое правило выводится в форме промежуточного выражения, маркированного символом (@code{%t}).

Вызов @code{disprule (all)} выводит все определенные правила.

Функция @code{disprule} не вычисляет свои аргументы.
Функция @code{disprule} возвращает список меток промежуточных выражений, соответствующих выведенным правилам.

См. также функцию @code{letrules}, которая выводит правила определенные @code{let}.

Примеры:

@c ===beg===
@c tellsimpafter (foo (x, y), bar (x) + baz (y));
@c tellsimpafter (x + y, special_add (x, y));
@c defmatch (quux, mumble (x));
@c disprule (foorule1, "+rule1", quux);
@c ''%;
@c ===end===
@example
(%i1) tellsimpafter (foo (x, y), bar (x) + baz (y));
(%o1)                   [foorule1, false]
(%i2) tellsimpafter (x + y, special_add (x, y));
(%o2)                   [+rule1, simplus]
(%i3) defmatch (quux, mumble (x));
(%o3)                         quux
(%i4) disprule (foorule1, "+rule1", quux);
(%t4)        foorule1 : foo(x, y) -> baz(y) + bar(x)

(%t5)          +rule1 : y + x -> special_add(x, y)

(%t6)                quux : mumble(x) -> []

(%o6)                    [%t4, %t5, %t6]
(%i6) ''%;
(%o6) [foorule1 : foo(x, y) -> baz(y) + bar(x), 
     +rule1 : y + x -> special_add(x, y), quux : mumble(x) -> []]
@end example

@opencatbox
@category{Правила преобразования и шаблоны} @category{Функции вывода}
@closecatbox
@end deffn

@deffn {Функция} let (@var{prod}, @var{repl}, @var{predname}, @var{arg_1}, ..., @var{arg_n})
@deffnx {Функция} let ([@var{prod}, @var{repl}, @var{predname}, @var{arg_1}, ..., @var{arg_n}],  @var{package_name})
Определяет правила подстановки для функции @code{letsimp} такие, что @var{prod} заменяется на @var{repl}.
@var{prod} является произведением подвыражений положительной или  отрицательной степени. 
Подвыражения могут быть следующего типа:

@itemize @bullet
@item
Атомы, поиск которых @code{letsimp} ведет только по имени, если перед
вызовом  @code{letsimp} в функции @code{matchdeclare} не был определен
предикат, связанный с этим атомом.  В последнем случае @code{letsimp}
будет сопоставлять атом с любым членом произведения удовлетворяющим предикату.
@item
Ядра типа @code{sin(x)}, @code{n!}, @code{f(x,y)} и т.п.  Как и в
предыдущем случае @code{letsimp} ищет буквальное соответствие, если
в @code{matchdeclare} не был определен предикат.
@end itemize

Члены положительной степени будут сопоставляться только членам, имеющим положительную
степень. Члены отрицательной степени будут сопоставляться только членам, имеющим отрицательную
степень. 
Для  того чтобы @code{letsimp} работал с отрицательными степенями в @var{prod} 
переменная  @code{letrat} должна быть установлена равной @code{true}.
См. также @code{letrat}.

Если в функцию @code{let} включен предикат, с последующим списком аргументов,
то подстановки осуществляются только если  @code{predname (arg_1', ...,
arg_n')} дает @code{true}, где @var{arg_i'} есть значение, сопоставленное  @var{arg_i}. 
Переменная @var{arg_i} может быть именем атома или аргументом любого ядра, присутствующего в @var{prod}.
@var{repl} может быть любым  рациональным выражением. @c ONLY RATIONAL -- REALLY ??
Если любой атом или аргумент из @var{prod} присутствует в
@var{repl}, то выполняются соответствующие подстановки. @c SPELL OUT "APPROPRIATE" IN THIS CONTEXT

Глобальная переменная @code{letrat} управляет упрощением дробных
выражений в @code{letsimp}.
Если @code{letrat} равена @code{false}, то
@code{letsimp} упрощает отдельно числитель и знаменатель выражения
@var{expr}, но не упрощает их частное.
В этом случае подстановки типа @code{n!/n} на @code{(n-1)!} не будут работать.
Если @code{letrat} равена @code{true}, тогда числитель, знаменатель и
их частное упрощаются в данном порядке.

Данные функции подстановок позволяют работать с несколькими пакетами
правил одновременно. Каждый пакет правил может содержать любое
количество правил преобразований @code{let} и обозначается некоторым
заданным пользователем именем.
Вызов @code{let ([@var{prod}, @var{repl}, @var{predname}, @var{arg_1}, ..., @var{arg_n}], @var{package_name})}
добавляет правило @var{predname} к пакету правил @var{package_name}.
Вызов @code{letsimp (@var{expr}, @var{package_name})}
применяет правила преобразований из пакета @var{package_name}.
Процедура @code{letsimp (@var{expr}, @var{package_name1}, @var{package_name2}, ...)}
эквивалентна применению функций @code{letsimp (@var{expr}, @var{package_name1})}
и затем функции @code{letsimp (%, @var{package_name2})}, ....

Переменная @code{current_let_rule_package} содержит имя текущего пакета правил.
Данной переменной может быть присвоено имя любого пакета правил,
определенного при помощи @code{let}.
Вызов команды @code{let} без упоминания имени пакета приводит к
применению пакета, определенного @code{current_let_rule_package}.
При вызове типа @code{letsimp (@var{expr}, @var{rule_pkg_name})},
используются правила пакета @var{rule_pkg_name}, только для данного вызова @code{lrtsimp} а 
значение переменной  @code{current_let_rule_package}
не меняется. По умолчанию @code{current_let_rule_package} равно @code{default_let_rule_package}.

@example
(%i1) matchdeclare ([a, a1, a2], true)$
(%i2) oneless (x, y) := is (x = y-1)$
(%i3) let (a1*a2!, a1!, oneless, a2, a1);
(%o3)         a1 a2! --> a1! where oneless(a2, a1)
(%i4) letrat: true$
(%i5) let (a1!/a1, (a1-1)!);
                        a1!
(%o5)                   --- --> (a1 - 1)!
                        a1
(%i6) letsimp (n*m!*(n-1)!/m);
(%o6)                      (m - 1)! n!
(%i7) let (sin(a)^2, 1 - cos(a)^2);
                        2               2
(%o7)                sin (a) --> 1 - cos (a)
(%i8) letsimp (sin(x)^4);
                        4           2
(%o8)                cos (x) - 2 cos (x) + 1
@end example

@c NEEDS ADDITIONAL EXAMPLES

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@defvr {Управляющая переменная} letrat
Значение по умолчанию: @code{false}

Если @code{letrat} равна @code{false}, то @code{letsimp} упрощает отдельно числитель и знаменатель выражения
@var{expr}, и не упрощает их частное.

Если @code{letrat} равна @code{true}, то числитель, знаменатель и их частное упрощаются в данном порядке.

@example
(%i1) matchdeclare (n, true)$
(%i2) let (n!/n, (n-1)!);
                         n!
(%o2)                    -- --> (n - 1)!
                         n
(%i3) letrat: false$
(%i4) letsimp (a!/a);
                               a!
(%o4)                          --
                               a
(%i5) letrat: true$
(%i6) letsimp (a!/a);
(%o6)                       (a - 1)!
@end example

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end defvr

@c NEEDS EXAMPLES
@deffn {Функция} letrules ()
@deffnx {Функция} letrules (@var{package_name})
Выводит правила, содержащиеся в пакете правил преобразований.
@code{letrules ()} выводит правила текущего пакета правил
преобразований.
@code{letrules (@var{package_name})} выводит правила преобразований в
пакете @var{package_name}.

Текущий пакет правил определяется значением @code{current_let_rule_package}.
Если не определено иначе, то @code{current_let_rule_package}
по умолчанию равен @code{default_let_rule_package}.

См. также функцию @code{disprule}, отображающую правила, определенные
путем @code{tellsimp} и @code{tellsimpafter}.
@c WHAT ABOUT defmatch AND defrule ??

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@deffn {Функция} letsimp (@var{expr})
@deffnx {Функция} letsimp (@var{expr}, @var{package_name})
@deffnx {Функция} letsimp (@var{expr}, @var{package_name_1}, ..., @var{package_name_n})
Данная функция осуществляет повторное применение правил подстановки,
определенных в @code{let}, до тех пор пока выражение @var{expr} не
перестанет изменяться.

@code{letsimp (@var{expr})} использует правила из пакета @code{current_let_rule_package}.

@code{letsimp (@var{expr}, @var{package_name})} использует правила из пакета @var{package_name}
без изменения значения переменной @code{current_let_rule_package}.

@code{letsimp (@var{expr}, @var{package_name_1}, ..., @var{package_name_n})}
эквивалентно применению  @code{letsimp (@var{expr}, @var{package_name_1}},
затем @code{letsimp (%, @var{package_name_2})} и так далее.

@c NEEDS EXAMPLES
@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@defvr {Управляющая переменная} let_rule_packages
Значение по умолчанию: @code{[default_let_rule_package]}

@code{let_rule_packages} - список определенных пользователем пакетов
правил вместе с пакетом @code{default_let_rule_package}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end defvr

@deffn {Функция} matchdeclare (@var{a_1}, @var{pred_1}, ..., @var{a_n}, @var{pred_n})
Связывает предикат @var{pred_k} с переменной или списком переменных
@var{a_k}, так что  @var{a_k} сопоставляется с выражениями,
для которых предикат возвращает значение отличное от @code{false}.

Предикат это есть имя функции, или лямбда-выражение, или вызов функции 
или лямбда-выражения без последнего аргумента, или @code{true}, или @code{all}.
Если предикат определен при помощи вызова функции или лямбда-выражения, то 
тестируемое выражение добавляется к списку аргументов; аргументы вычисляются 
во время вызова процедуры проверки на соответствие. 
Если предикат определен в виде имени функции или лямбда-выражения, 
то единственным аргументом является тестируемое выражение.
Предикат не обязан быть определенным в момент вызова
@code{matchdeclare}, поскольку он не вычисляется до тех пор пока 
не вызывается проверка на соответствие.

Предикат может возвращать логическое выражение а также @code{true} или @code{false}.
Логическое выражение вычисляется при помощи @code{is} внутри построенной функции правила,
так что нет необходимости вызывать @code{is} в предикате.

Если выражение удовлетворяет предикату, то переменной шаблона
присваивается выражение за исключением переменных шаблона которые
являются операндами сложения  @code{+} или умножения @code{*}. 
Только сложение и умножение управляется специальным образом. Другие n-арные операторы,
(как пользовательские, так и встроенные) рассматриваются как обычные функции.
@c WOULD BE GREAT TO EXTEND PART+/PART* PROCESSING TO ALL N-ARY OPERATORS

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

Алгоритм проверки шаблонов, содержащий суммы и произведения, 
может давать разные результаты (например,  шаблон, содержащий переменную соответствующую
"всему, что угодно") в зависимости от порядка 
членов заданного шаблона и порядка членов тестируемого выражения. 
Если все операторы предикаты взаимно исключают друг друга, то результат не зависит от порядка, 
поскольку члены, соответствующие одному предикату, не могут соответствовать другому.

Вызов  @code{matchdeclare} с переменной  @var{a} в качестве аргумента
изменяет ранее объявленные свойства  @code{matchdeclare} для @var{a} -
при определении правил преобразования, учитываются только самый последний 
вызов @code{matchdeclare}. 
Все последующие изменения свойства @code{matchdeclare} 
(посредством @code{matchdeclare} или @code{remove}) 
не меняют существующих правил преобразований.

@code{propvars (matchdeclare)} возвращает список всех переменных,
имеющих свойство @code{matchdeclare}.
@code{printprops (@var{a}, matchdeclare)} возвращает предикат
для переменной @code{a}.
@code{printprops (all, matchdeclare)} возвращает список всех предикатов
для всех переменных @code{matchdeclare}.
@code{remove (@var{a}, matchdeclare)} удаляет свойства
@code{matchdeclare} для переменной @var{a}.

Функции
@code{defmatch}, @code{defrule}, @code{tellsimp}, @code{tellsimpafter} и @code{let}
строят правила, которые сопоставляют выражения с шаблонами.

Функция @code{matchdeclare} не вычисляет свои аргументы.
Функция @code{matchdeclare} всегда возвращает @code{done}.

Примеры:

Предикат есть имя функции, или лямбда-выражение, или вызов функции или 
лямбда-вызов без последнего аргумента,
или @code{true}, или @code{all}.

@c ===beg===
@c matchdeclare (aa, integerp);
@c matchdeclare (bb, lambda ([x], x > 0));
@c matchdeclare (cc, freeof (%e, %pi, %i));
@c matchdeclare (dd, lambda ([x, y], gcd (x, y) = 1) (1728));
@c matchdeclare (ee, true);
@c matchdeclare (ff, all);
@c ===end===
@example
(%i1) matchdeclare (aa, integerp);
(%o1)                         done
(%i2) matchdeclare (bb, lambda ([x], x > 0));
(%o2)                         done
(%i3) matchdeclare (cc, freeof (%e, %pi, %i));
(%o3)                         done
(%i4) matchdeclare (dd, lambda ([x, y], gcd (x, y) = 1) (1728));
(%o4)                         done
(%i5) matchdeclare (ee, true);
(%o5)                         done
(%i6) matchdeclare (ff, all);
(%o6)                         done
@end example

Если выражение удовлетворяет предикату, то переменной 
шаблона присваивается выражение.

@c ===beg===
@c matchdeclare (aa, integerp, bb, atom);
@c defrule (r1, bb^aa, ["integer" = aa, "atom" = bb]);
@c r1 (%pi^8);
@c ===end===
@example
(%i1) matchdeclare (aa, integerp, bb, atom);
(%o1)                         done
(%i2) defrule (r1, bb^aa, ["integer" = aa, "atom" = bb]);
                    aa
(%o2)        r1 : bb   -> [integer = aa, atom = bb]
(%i3) r1 (%pi^8);
(%o3)               [integer = 8, atom = %pi]
@end example

В случае суммы и произведения,
переменной шаблона может быть присвоено простое выражение, которое
удовлетворяет предикату, или также сумма или произведение 
таких выражений.
@c ===beg===
@c matchdeclare (aa, atom, bb, lambda ([x], not atom(x)));
@c defrule (r1, aa + bb, ["all atoms" = aa, "all nonatoms" = 
@c                bb]);
@c r1 (8 + a*b + sin(x));
@c defrule (r2, aa * bb, ["all atoms" = aa, "all nonatoms" = 
@c                bb]);
@c r2 (8 * (a + b) * sin(x));
@c ===end===
@example
(%i1) matchdeclare (aa, atom, bb, lambda ([x], not atom(x)));
(%o1)                         done
(%i2) defrule (r1, aa + bb, ["all atoms" = aa, "all nonatoms" =
               bb]);
bb + aa partitions `sum'
(%o2)  r1 : bb + aa -> [all atoms = aa, all nonatoms = bb]
(%i3) r1 (8 + a*b + sin(x));
(%o3)     [all atoms = 8, all nonatoms = sin(x) + a b]
(%i4) defrule (r2, aa * bb, ["all atoms" = aa, "all nonatoms" =
               bb]);
bb aa partitions `product'
(%o4)   r2 : aa bb -> [all atoms = aa, all nonatoms = bb]
(%i5) r2 (8 * (a + b) * sin(x));
(%o5)    [all atoms = 8, all nonatoms = (b + a) sin(x)]
@end example

При сопоставлении аргументов @code{+} и @code{*},
если все предикаты условия являются взаимоисключающими, то результат
проверки не зависит порядка, так как один предикат не соответствует
членам, соответствующим другому предикату.

@c ===beg===
@c matchdeclare (aa, atom, bb, lambda ([x], not atom(x)));
@c defrule (r1, aa + bb, ["all atoms" = aa, "all nonatoms" = 
@c                bb]);
@c r1 (8 + a*b + %pi + sin(x) - c + 2^n);
@c defrule (r2, aa * bb, ["all atoms" = aa, "all nonatoms" = 
@c                bb]);
@c r2 (8 * (a + b) * %pi * sin(x) / c * 2^n);
@c ===end===
@example
(%i1) matchdeclare (aa, atom, bb, lambda ([x], not atom(x)));
(%o1)                         done
(%i2) defrule (r1, aa + bb, ["all atoms" = aa, "all nonatoms" =
               bb]);
bb + aa partitions `sum'
(%o2)  r1 : bb + aa -> [all atoms = aa, all nonatoms = bb]
(%i3) r1 (8 + a*b + %pi + sin(x) - c + 2^n);
                                                     n
(%o3) [all atoms = %pi + 8, all nonatoms = sin(x) + 2  - c + a b]
(%i4) defrule (r2, aa * bb, ["all atoms" = aa, "all nonatoms" =
               bb]);
bb aa partitions `product'
(%o4)   r2 : aa bb -> [all atoms = aa, all nonatoms = bb]
(%i5) r2 (8 * (a + b) * %pi * sin(x) / c * 2^n);
                                                  n
                                         (b + a) 2  sin(x)
(%o5) [all atoms = 8 %pi, all nonatoms = -----------------]
                                                 c
@end example

Функции @code{propvars} и @code{printprops} возвращают информацию о
переменных шаблона.

@c ===beg===
@c matchdeclare ([aa, bb, cc], atom, [dd, ee], integerp);
@c matchdeclare (ff, floatnump, gg, lambda ([x], x > 100));
@c propvars (matchdeclare);
@c printprops (ee, matchdeclare);
@c printprops (gg, matchdeclare);
@c printprops (all, matchdeclare);
@c ===end===
@example
(%i1) matchdeclare ([aa, bb, cc], atom, [dd, ee], integerp);
(%o1)                         done
(%i2) matchdeclare (ff, floatnump, gg, lambda ([x], x > 100));
(%o2)                         done
(%i3) propvars (matchdeclare);
(%o3)             [aa, bb, cc, dd, ee, ff, gg]
(%i4) printprops (ee, matchdeclare);
(%o4)                    [integerp(ee)]
(%i5) printprops (gg, matchdeclare);
(%o5)              [lambda([x], x > 100, gg)]
(%i6) printprops (all, matchdeclare);
(%o6) [lambda([x], x > 100, gg), floatnump(ff), integerp(ee), 
                      integerp(dd), atom(cc), atom(bb), atom(aa)]
@end example

@opencatbox
@category{Правила преобразования и шаблоны} @category{Факты и выводы}
@closecatbox
@end deffn

@deffn {Функция} matchfix (@var{ldelimiter}, @var{rdelimiter})
@deffnx {Функция} matchfix (@var{ldelimiter}, @var{rdelimiter}, @var{arg_pos}, @var{pos})
Объявляет матчфиксный (matchfix) оператор с левым и правым ограничителями 
@var{ldelimiter} и @var{rdelimiter} соответственно. Ограничители являются строками.

Матчфиксный оператор является функцией любого количества аргументов
заключенных между ограничителями @var{ldelimiter} и @var{rdelimiter}. 
Ограничителем может являться любая строка, если синтаксический анализатор 
может различить ограничители от других выражений и операторов.
На практике, это исключает такие ограничители, как
@code{%}, @code{,}, @code{$} и @code{;}, и может потребовать при вводе
изолировать ограничители пробелами. Правый ограничитель может
совпадать с левым или отличаться от него. 

Левый ограничитель может быть ассоциирован только с одним правым; 
два различных матчфиксных оператора не могут иметь
одинаковых левых ограничителя. 

Существующий оператор может быть переобъявлен, как матчфиксный оператор   
без изменения других его свойств. Например, встроенные
операторы сложения @code{+} могут быть объявлены матчфиксными, однако
операторные функции для встроенных операторов определены быть не могут.

Вызов @code{matchfix (@var{ldelimiter}, @var{rdelimiter}, @var{arg_pos}, @var{pos})} 
объявляет аргумент "часть речи" @var{arg_pos} и результат "часть речи" @var{pos} 
вместе с ограничителями @var{ldelimiter} и @var{rdelimiter}.

Термин "чать речи" по отношению к декларации операторов означает тип выражения.
Различаются три типа выражений: @code{expr}, @code{clause} и @code{any},
что обозначает алгебраическое выражение, логическое выражение и выражение
произвольного типа соответственно.  Maxima может обнаруживать некоторые
синтаксические ошибки сравнивая объявленную часть речи с реальным
выражением.

@c DUNNO IF WE REALLY NEED TO MENTION BINDING POWER HERE -- AS NOTED IT'S IRRELEVANT
@c An operator declared by @code{matchfix} is assigned a low binding power.
@c Since a matchfix operator must be evaluated before any expression
@c which contains it,
@c binding power is effectively irrelevant
@c to the declaration of a matchfix operator.

Функция для выполнения матчфиксной операции является обычной пользовательской
функцией.  Операторная функция определяется стандартным образом 
при помощи операторов @code{:=} или @code{define}.
Аргументы могут быть записаны между ограничителями или при
помощи левого ограничителя в форме строки и последующих аргументов
в скобках.
@code{dispfun (@var{ldelimiter})} выводит определение
функции. 

Единственный встроенный матчфиксный оператор это конструктор
списка @code{[ ]}. Скобки @code{( )} и двойные кавычки @code{" "} 
работают как матчфиксные операторы, однако не обрабатываются
синтаксическим анализатором Maxima как таковые.

Функция @mcode{matchfix} вычисляет свои аргументы.
Функция @code{matchfix} возвращает свой первый аргумент @var{ldelimiter}.
@c HOW TO TAKE AWAY THE MATCHFIX PROPERTY ??

Примеры:

@itemize @bullet
@item
В качестве ограничителей можно задавать практически любые строки.
@end itemize
@c ===beg===
@c matchfix ("@@", "~");
@c @@ a, b, c ~;
@c matchfix (">>", "<<");
@c >> a, b, c <<;
@c matchfix ("foo", "oof");
@c foo a, b, c oof;
@c >> w + foo x, y oof + z << / @@ p, q ~;
@c ===end===
@example
(%i1) matchfix ("@@@@", "~");
(%o1)                          @@@@
(%i2) @@@@ a, b, c ~;
(%o2)                      @@@@a, b, c~
(%i3) matchfix (">>", "<<");
(%o3)                          >>
(%i4) >> a, b, c <<;
(%o4)                      >>a, b, c<<
(%i5) matchfix ("foo", "oof");
(%o5)                          foo
(%i6) foo a, b, c oof;
(%o6)                     fooa, b, coof
(%i7) >> w + foo x, y oof + z << / @@@@ p, q ~;
                     >>z + foox, yoof + w<<
(%o7)                ----------------------
                            @@@@p, q~
@end example

@itemize @bullet
@item
Матчфиксные операторы -- это обычные пользовательские функции.
@end itemize
@example
(%i1) matchfix ("!-", "-!");
(%o1)                         "!-"
(%i2) !- x, y -! := x/y - y/x;
                                    x   y
(%o2)                   !-x, y-! := - - -
                                    y   x
(%i3) define (!-x, y-!, x/y - y/x);
                                    x   y
(%o3)                   !-x, y-! := - - -
                                    y   x
(%i4) define ("!-" (x, y), x/y - y/x);
                                    x   y
(%o4)                   !-x, y-! := - - -
                                    y   x
(%i5) dispfun ("!-");
                                    x   y
(%t5)                   !-x, y-! := - - -
                                    y   x

(%o5)                         done
(%i6) !-3, 5-!;
                                16
(%o6)                         - --
                                15
(%i7) "!-" (3, 5);
                                16
(%o7)                         - --
                                15
@end example

@opencatbox
@category{Синтаксис} @category{Операторы}
@closecatbox
@end deffn

@c NEEDS CLARIFICATION AND EXAMPLES
@deffn {Функция} remlet (@var{prod}, @var{name})
@deffnx {Функция} remlet ()
@deffnx {Функция} remlet (all)
@deffnx {Функция} remlet (all, @var{name})
Удаляет правило подстановки @var{prod} -> замена, 
определенное при самом последнем вызове функции @code{let}.  
При вызове с именем правила в качестве аргумента 
удаление производится из соответствующего пакета правил.

Вызовы @code{remlet()} и @code{remlet(all)} удаляют все правила
подстановки из текущего пакета правил. При указании имени, например,
@code{remlet (all, @var{name})}, пакет правил @var{name} также удаляется.

Если необходимо изменить правило подстановки одного 
произведения, нет необходимости вызывать @code{remlet}, можно просто
переопределить подстановку данного произведения при помощи функции
@code{let}, с новой заменой и/или предикатом.
После этого вызов @code{remlet (@var{prod})} восстанавливает исходное
правило подстановки.

См. также функцию @code{remrule}, которая удаляет правила
определенные функцией  @code{tellsimp} или @code{tellsimpafter}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@deffn {Функция} remrule (@var{op}, @var{rulename})
@deffnx {Функция} remrule (@var{op}, all)
Удаляет правила, определенные функциями @code{tellsimp} или @code{tellsimpafter}.

@code{remrule (@var{op}, @var{rulename})}
удаляет правило с именем @var{rulename} для оператора @var{op}.
Если оператор @var{op} является встроенным оператором или определен
пользователем (например, при помощи функций @code{infix}, @code{prefix},
и т.п.), тогда @var{op} и @var{rulename} необходимо заключить в двойные кавычки.

@code{remrule (@var{op}, all)} удаляет все правила для оператора @var{op}.

См. также функцию @code{remlet}, удаляющую правила, определенные при помощи @code{let}.

Примеры:

@c ===beg===
@c tellsimp (foo (aa, bb), bb - aa);
@c tellsimpafter (aa + bb, special_add (aa, bb));
@c infix ("@@");
@c tellsimp (aa @@ bb, bb/aa);
@c tellsimpafter (quux (%pi, %e), %pi - %e);
@c tellsimpafter (quux (%e, %pi), %pi + %e);
@c [foo (aa, bb), aa + bb, aa @@ bb, quux (%pi, %e), 
@c        quux (%e, %pi)];
@c remrule (foo, foorule1);
@c remrule ("+", "+rule1");
@c remrule ("@@", "@@rule1");
@c remrule (quux, all);
@c [foo (aa, bb), aa + bb, aa @@ bb, quux (%pi, %e), 
@c         quux (%e, %pi)];
@c ===end===
@example
(%i1) tellsimp (foo (aa, bb), bb - aa);
(%o1)                   [foorule1, false]
(%i2) tellsimpafter (aa + bb, special_add (aa, bb));
(%o2)                   [+rule1, simplus]
(%i3) infix ("@@@@");
(%o3)                          @@@@
(%i4) tellsimp (aa @@@@ bb, bb/aa);
(%o4)                   [@@@@rule1, false]
(%i5) tellsimpafter (quux (%pi, %e), %pi - %e);
(%o5)                  [quuxrule1, false]
(%i6) tellsimpafter (quux (%e, %pi), %pi + %e);
(%o6)             [quuxrule2, quuxrule1, false]
(%i7) [foo (aa, bb), aa + bb, aa @@@@ bb, quux (%pi, %e),
       quux (%e, %pi)];
                                     bb
(%o7) [bb - aa, special_add(aa, bb), --, %pi - %e, %pi + %e]
                                     aa
(%i8) remrule (foo, foorule1);
(%o8)                          foo
(%i9) remrule ("+", "+rule1");
(%o9)                           +
(%i10) remrule ("@@@@", "@@@@rule1");
(%o10)                         @@@@
(%i11) remrule (quux, all);
(%o11)                        quux
(%i12) [foo (aa, bb), aa + bb, aa @@@@ bb, quux (%pi, %e),
        quux (%e, %pi)];
(%o12) [foo(aa, bb), bb + aa, aa @@@@ bb, quux(%pi, %e), 
                                         quux(%e, %pi)]
@end example

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@c NEEDS EXPANSION OR MAYBE JUST APPROPRIATE REFS TO tellsimpafter
@deffn {Функция} tellsimp (@var{pattern}, @var{replacement})
аналогична @code{tellsimpafter}, но добавляет
новую информацию о правилах до уже существующей. Таким образом, сначала
применяются пользовательские правила упрощения, а потом правила,
встроенные в систему.

Функция @code{tellsimp} используется, когда важно модифицировать выражение
до того, как оно обработано упрощателем, например, встроенный механизм
упрощения "знает" что-либо о структуре выражения, но возвращает результат,
который вас не устраивает. Если встроенный механизм
упрощения "знает" что-либо о главном операторе выражения, но работает не
достаточно эффективно - можно попробовать использовать @code{tellsimpafter}.

Шаблон не может быть суммой, произведением, одиночной переменной или числом.

@code{rules} - список правил определенный функциями
@code{defrule}, @code{defmatch}, @code{tellsimp} и @code{tellsimpafter}.

Примеры:

@example
(%i1) matchdeclare (x, freeof (%i));
(%o1)                         done
(%i2) %iargs: false$
(%i3) tellsimp (sin(%i*x), %i*sinh(x));
(%o3)                 [sinrule1, simp-%sin]
(%i4) trigexpand (sin (%i*y + x));
(%o4)         sin(x) cos(%i y) + %i cos(x) sinh(y)
(%i5) %iargs:true$
(%i6) errcatch(0^0);
 0
0  has been generated
(%o6)                          []
(%i7) ev (tellsimp (0^0, 1), simp: false);
(%o7)                  [^rule1, simpexpt]
(%i8) 0^0;
(%o8)                           1
(%i9) remrule ("^", %th(2)[1]);
(%o9)                           ^
(%i10) tellsimp (sin(x)^2, 1 - cos(x)^2);
(%o10)                 [^rule2, simpexpt]
(%i11) (1 + sin(x))^2;
                                      2
(%o11)                    (sin(x) + 1)
(%i12) expand (%);
                                   2
(%o12)               2 sin(x) - cos (x) + 2
(%i13) sin(x)^2;
                                  2
(%o13)                     1 - cos (x)
(%i14) kill (rules);
(%o14)                        done
(%i15) matchdeclare (a, true);
(%o15)                        done
(%i16) tellsimp (sin(a)^2, 1 - cos(a)^2);
(%o16)                 [^rule3, simpexpt]
(%i17) sin(y)^2;
                                  2
(%o17)                     1 - cos (y)
@end example

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@deffn {Функция} tellsimpafter (@var{pattern}, @var{replacement})
Определяет правило упрощения, которое встроенный в Maxima механизм
упрощения применяет после встроенных правил упрощения.
@var{pattern} - выражение, включающее переменные шаблона (объявленные в @code{matchdeclare})
и другие атомы и операторы, которые рассматриваются как константы с точки зрения сопоставления с шаблоном.
@var{replacement} подставляется вместо первоначального выражения, удовлетворяющего шаблону @var{pattern};
переменным шаблона из в @var{replacement} присваиваются соответствующие подвыражения из
реального выражения.

@var{pattern} может быть любым составным выражением в котором имя главного
оператор не входит в число переменных шаблона;
правило упрощения связывается с именем главного оператора.
Имена функций (за исключением приведенных ниже), списки и массивы могут присутствовать
в шаблоне  @var{pattern} в качестве основного оператора только, как
литералы (не переменные шаблона);
это исключает шаблоны вида @code{aa(x)} и @code{bb[y]},
если @code{aa} и @code{bb} являются переменными шаблона.
Имена функций, списки и массивы, которые являются переменными шаблона
могут входить в качестве не основных операторов в описание шаблона @var{pattern}.

Есть одно исключение к указанному правилу, касающееся имен функций.
Имена функций с индексом в выражениях типа @code{aa[x](y)}
могут быть переменными шаблона, поскольку в этом случае главный оператор 
не  @code{aa}, а Lisp-атом @code{mqapply}.
Это является следствием представления выражений, включающих
функции с индексом.

@c LET'S NOT GO INTO DETAILS ABOUT MAIN OPERATORS HERE; BUT PRESERVE THIS FOR REFERENCE
@c The main operator of an expression @code{expr} is @code{caar $expr}.
@c For most kinds of expressions,
@c the main operator is the operator returned by @code{op (@var{pattern})};
@c the sole exception is the operator @code{mqapply},
@c which appears in indexed function expressions (e.g., @code{foo[i](x)}).

@c NEED TO REVIEW THIS PARAGRAPH FOR ACCURACY
Правила упрощения применяются после вычисления (если вычисления не
запрещены либо экранированием выражения, либо ключом @code{noeval}).
Правила введенные @code{tellsimpafter} применяются в том порядке в
котором они были определены после всех встроенных правил.
Преобразования применяются "снизу-вверх", т.е.,
сначала к подвыражению, перед обработкой выражения в  целом.
@c NO IT IS MORE COMPLICATED THAN THIS, ALTHOUGH IN SOME CIRCUMSTANCE IT APPEARS TO BE THE CASE:
@c For a given expression, at most one rule per operator is applied.
Иногда для того, чтобы обеспечить, что применены все правила, необходимо повторное упрощение результата 
(например, при применении оператора кавычка-кавычка @code{'@w{}'} или ключа @code{infeval}).

Переменные шаблона рассматриваются как локальные переменные в правилах
упрощения. Как только правило определено, значение переменной шаблона
не  влияет на правило, и наоборот, правило не влияет на значение переменной.
Присваивание значений переменным шаблона, происходящее в результате успешного
сопоставления шаблона, не влияет на текущие значения (или их отсутствие)
переменных шаблона. Однако, как и у всех атомов в Maxima,
свойства переменных шаблона (объявленные оператором  @code{put}
и подобными функциями) являются глобальными.

Правило, построенное с помощью @code{tellsimpafter},
обозначаеся именем главного оператора @var{pattern}.
Правила для встроенных операторов и пользовательских функций,
определенных  при помощи @code{infix}, @code{prefix}, 
@code{postfix}, @code{matchfix} и @code{nofix},
имеют имена, являющиеся Lisp-идентификаторами.
@c SLIGHTLY TOO MUCH DETAIL
@c (that is, the name is written with a leading question mark @code{?} in Maxima).
Правила для других функций имеют имена, являющиеся идентификаторами Maxima.
@c SLIGHTLY TOO MUCH DETAIL
@c (that is, the name begins with dollar sign @code{$}).

Обработка вычисляемых и не вычисляемых форм немного неоднозначна. @c THIS IS A BUG.
Если правило определено для невычисляемой (или вычисляемой) формы
выражения, а правило для соответствующей вычисляемой (или невычисляемой) 
уже существует, то новое правило применяется к обеим формам
выражения (вычисляемой и невычисляемой).
Если правило для соответствующей вычисляемой (или невычисляемой) 
не существует, то новое правило применяется к невычисляемой 
(или вычисляемой) форме выражения.

Правило, построенное с помощью @code{tellsimpafter}, является обычной
Lisp- функцией. Если имя правила - @code{$foorule1}, то
конструкция @code{:lisp (trace $foorule1)} дает трассировку ее вызовов, 
а @code{:lisp (symbol-function '$foorule1} выводит ее определение.

Функция @code{tellsimpafter} не вычисляет свои аргументы.
Функция @code{tellsimpafter} возвращает список правил для основного оператора
шаблона @var{pattern}, включая вновь объявленные правила.
@c WHAT IS simpfoo THAT SOMETIMES APPEARS, AND WHY DOES false SOMETIMES APPEAR IN RETURN VALUE ??

См. также @code{matchdeclare}, @code{defmatch}, @code{defrule}, @code{tellsimp}, @code{let},
@code{kill}, @code{remrule} и @code{clear_rules}.

Примеры:

@var{pattern} может быть любым неатомарным выражением в котором главный
оператор не является переменной шаблона.

@c ===beg===
@c matchdeclare (aa, atom, [ll, mm], listp, xx, true)$
@c tellsimpafter (sin (ll), map (sin, ll));
@c sin ([1/6, 1/4, 1/3, 1/2, 1]*%pi);
@c tellsimpafter (ll^mm, map ("^", ll, mm));
@c [a, b, c]^[1, 2, 3];
@c tellsimpafter (foo (aa (xx)), aa (foo (xx)));
@c foo (bar (u - v));
@c ===end===
@example
(%i1) matchdeclare (aa, atom, [ll, mm], listp, xx, true)$
(%i2) tellsimpafter (sin (ll), map (sin, ll));
(%o2)                 [sinrule1, simp-%sin]
(%i3) sin ([1/6, 1/4, 1/3, 1/2, 1]*%pi);
                    1  sqrt(2)  sqrt(3)
(%o3)              [-, -------, -------, 1, 0]
                    2     2        2
(%i4) tellsimpafter (ll^mm, map ("^", ll, mm));
(%o4)                  [^rule1, simpexpt]
(%i5) [a, b, c]^[1, 2, 3];
                                2   3
(%o5)                      [a, b , c ]
(%i6) tellsimpafter (foo (aa (xx)), aa (foo (xx)));
(%o6)                   [foorule1, false]
(%i7) foo (bar (u - v));
(%o7)                    bar(foo(u - v))
@end example

Правила применяются в том порядке в котором они были определены.
Если два правила соответствуют выражению, то первым
применяется то, которое было определено раньше.

@c ===beg===
@c matchdeclare (aa, integerp);
@c tellsimpafter (foo (aa), bar_1 (aa));
@c tellsimpafter (foo (aa), bar_2 (aa));
@c foo (42);
@c ===end===
@example
(%i1) matchdeclare (aa, integerp);
(%o1)                         done
(%i2) tellsimpafter (foo (aa), bar_1 (aa));
(%o2)                   [foorule1, false]
(%i3) tellsimpafter (foo (aa), bar_2 (aa));
(%o3)              [foorule2, foorule1, false]
(%i4) foo (42);
(%o4)                       bar_1(42)
@end example

Переменные шаблона являются локальными переменные правил упрощения.
(Сравни с  функцией @code{defmatch}, которая рассматривает переменные
шаблона, как глобальные).

@c ===beg===
@c matchdeclare (aa, integerp, bb, atom);
@c tellsimpafter (foo(aa, bb), bar('aa=aa, 'bb=bb));
@c bb: 12345;
@c foo (42, %e);
@c bb;
@c ===end===
@example
(%i1) matchdeclare (aa, integerp, bb, atom);
(%o1)                         done
(%i2) tellsimpafter (foo(aa, bb), bar('aa=aa, 'bb=bb));
(%o2)                   [foorule1, false]
(%i3) bb: 12345;
(%o3)                         12345
(%i4) foo (42, %e);
(%o4)                 bar(aa = 42, bb = %e)
(%i5) bb;
(%o5)                         12345
@end example

Как и у всех атомов, свойства переменных шаблона
являются глобальными даже если их значение локально.
В данном примере свойство объявляется при помощи @code{define_variable}.
Это свойство атома @code{bb} является глобальным.

@c ===beg===
@c matchdeclare (aa, integerp, bb, atom);
@c tellsimpafter (foo(aa, bb), bar('aa=aa, 'bb=bb));
@c foo (42, %e);
@c define_variable (bb, true, boolean);
@c foo (42, %e);
@c ===end===
@example
(%i1) matchdeclare (aa, integerp, bb, atom);
(%o1)                         done
(%i2) tellsimpafter (foo(aa, bb), bar('aa=aa, 'bb=bb));
(%o2)                   [foorule1, false]
(%i3) foo (42, %e);
(%o3)                 bar(aa = 42, bb = %e)
(%i4) define_variable (bb, true, boolean);
(%o4)                         true
(%i5) foo (42, %e);
Error: bb was declared mode boolean, has value: %e
 -- an error.  Quitting.  To debug this try debugmode(true);
@end example

Правила именуются по имени основного оператора.
Имена правил для встроенных и пользовательских операторов
являются Lisp-идентификаторами, тогда как имена других функций 
являются идентификаторами Maxima.

@c ===beg===
@c tellsimpafter (foo (%pi + %e), 3*%pi);
@c tellsimpafter (foo (%pi * %e), 17*%e);
@c tellsimpafter (foo (%i ^ %e), -42*%i);
@c tellsimpafter (foo (9) + foo (13), quux (22));
@c tellsimpafter (foo (9) * foo (13), blurf (22));
@c tellsimpafter (foo (9) ^ foo (13), mumble (22));
@c rules;
@c foorule_name: first (%o1);
@c plusrule_name: first (%o4);
@c remrule (foo, foorule1);
@c remrule ("^", ?\^rule1);
@c rules;
@c ===end===
@example
(%i1) tellsimpafter (foo (%pi + %e), 3*%pi);
(%o1)                   [foorule1, false]
(%i2) tellsimpafter (foo (%pi * %e), 17*%e);
(%o2)              [foorule2, foorule1, false]
(%i3) tellsimpafter (foo (%i ^ %e), -42*%i);
(%o3)         [foorule3, foorule2, foorule1, false]
(%i4) tellsimpafter (foo (9) + foo (13), quux (22));
(%o4)                   [+rule1, simplus]
(%i5) tellsimpafter (foo (9) * foo (13), blurf (22));
(%o5)                  [*rule1, simptimes]
(%i6) tellsimpafter (foo (9) ^ foo (13), mumble (22));
(%o6)                  [^rule1, simpexpt]
(%i7) rules;
(%o7) [foorule1, foorule2, foorule3, +rule1, *rule1, ^rule1]
(%i8) foorule_name: first (%o1);
(%o8)                       foorule1
(%i9) plusrule_name: first (%o4);
(%o9)                        +rule1
(%i10) remrule (foo, foorule1);
(%o10)                         foo
(%i11) remrule ("^", ?\^rule1);
(%o11)                          ^
(%i12) rules;
(%o12)        [foorule2, foorule3, +rule1, *rule1]
@end example

Рабочий пример: антикоммутативное умножение.

@c ===beg===
@c gt (i, j) := integerp(j) and i < j;
@c matchdeclare (i, integerp, j, gt(i));
@c tellsimpafter (s[i]^^2, 1);
@c tellsimpafter (s[i] . s[j], -s[j] . s[i]);
@c s[1] . (s[1] + s[2]);
@c expand (%);
@c factor (expand (sum (s[i], i, 0, 9)^^5));
@c ===end===
@example
(%i1) gt (i, j) := integerp(j) and i < j;
(%o1)           gt(i, j) := integerp(j) and i < j
(%i2) matchdeclare (i, integerp, j, gt(i));
(%o2)                         done
(%i3) tellsimpafter (s[i]^^2, 1);
(%o3)                 [^^rule1, simpncexpt]
(%i4) tellsimpafter (s[i] . s[j], -s[j] . s[i]);
(%o4)                   [.rule1, simpnct]
(%i5) s[1] . (s[1] + s[2]);
(%o5)                    s  . (s  + s )
                          1     2    1
(%i6) expand (%);
(%o6)                      1 - s  . s
                                2    1
(%i7) factor (expand (sum (s[i], i, 0, 9)^^5));
(%o7) 100 (s  + s  + s  + s  + s  + s  + s  + s  + s  + s )
            9    8    7    6    5    4    3    2    1    0
@end example

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn

@deffn {Функция} clear_rules ()
Исполняет @code{kill (rules)} и обнуляет счетчик, т.е. новое правило
будет иметь номер @code{1} вслед за встроенными правилами для операторов суммы
@code{+}, умножения  @code{*} и степени @code{^}.

@opencatbox
@category{Правила преобразования и шаблоны}
@closecatbox
@end deffn
