@c English version 2011-06-13
@menu
* Introducción a reglas y patrones::  
* Funciones y variables sobre reglas y patrones::  
@end menu

@node Introducción a reglas y patrones, Funciones y variables sobre reglas y patrones, Reglas y patrones, Reglas y patrones
@section Introducción a reglas y patrones

Esta sección describe las reglas de simplificación y los patrones de comparación definidos por el usuario. Hay dos grupos de funciones que implementan diferentes esquemas de comparación de patrones. En un grupo están @code{tellsimp}, @code{tellsimpafter}, @code{defmatch}, @code{defrule}, @code{apply1}, @code{applyb1} y @code{apply2}. En el otro, se encuentran @code{let} y @code{letsimp}. Ambos esquemas definen patrones en términos de variables de patrones declaradas mediante  @code{matchdeclare}.

Las reglas de comparación de patrones definidas por @code{tellsimp} y @code{tellsimpafter} se aplican automáticamente por el simplificador de Maxima. Las reglas definidas por @code{defmatch}, @code{defrule} y @code{let} se aplican previa llamada a una función.

Hay otros mecanismos para las reglas; las relativas a polinomios se controlan mediante @code{tellrat} y las del álgebra conmutativa y no conmutativa se definen en el paquete @code{affine}.

@node Funciones y variables sobre reglas y patrones,  , Introducción a reglas y patrones, Reglas y patrones
@section Funciones y variables sobre reglas y patrones

@deffn {Función} apply1 (@var{expr}, @var{regla_1}, ..., @var{regla_n})

Aplica de forma repetida la @var{regla_1} a @var{expr} hasta que falla, a continuación aplica repetidamente la misma regla a todas las subexpresiones de @var{expr}, de izquierda a derecha, hasta que la @var{regla_1} haya fallado en todas las subexpresiones. Llámese @var{expr_2} al resultado de transformar @var{expr} de esta forma. Entonces la @var{regla_2} se aplica de la misma manera comenzando en el nivel superior de @var{expr_2}. Cuando la @var{regla_n} falla en la última expresión, se devuelve el resultado.

@code{maxapplydepth} es el nivel de las subexpresiones más internas procesadas por @code{apply1} y @code{apply2}.

Véase también @code{applyb1}, @code{apply2} y @code{let}.

@end deffn

@deffn {Función} apply2 (@var{expr}, @var{regla_1}, ..., @var{regla_n})

Si la @var{regla_1} falla en una subexpresión dada, entonces se aplica la @var{regla_2} repetidamente, etc. Sólo si todas las reglas fallan en una subexpresión serán aplicadas todas las reglas de forma repetida a la siguiente subexpresión. Si alguna de las reglas tiene éxito entonces la misma subexpresión es reprocesada, comenzando por la primera regla.

@code{maxapplydepth} es el nivel de las subexpresiones más internas procesadas por @code{apply1} y @code{apply2}.

Véase también @code{applyb1} y @code{let}.

@end deffn

@deffn {Función} applyb1 (@var{expr}, @var{regla_1}, ..., @var{regla_n})

Aplica la @var{regla_1} reiteradamente hasta la subexpresión más interna de @var{expr} hasta que falle, a continuación pasa a aplicar la misma regla en un nivel superior (esto es, en subexpresiones más grandes), hasta que la @var{regla_1} falle en la expresión de nivel más alto. Después se aplica la @var{regla_2} de la misma manera al resultado obtenido de @var{regla_1}. Tras la aplicación de la @var{regla_n} a la expresión de mayor nivel, se devuelve el resultado.

La función @code{applyb1} es similar a @code{apply1} pero opera de abajo-arriba, en lugar de arriba-abajo.

@code{maxapplyheight} es la máxima altura a la que llega @code{applyb1} antes de terminar su cometido.

Véase también @code{apply1}, @code{apply2} y @code{let}.

@end deffn

@defvr {Variable opcional} current_let_rule_package
Valor por defecto: @code{default_let_rule_package}

La variable @code{current_let_rule_package} es el nombre del paquete de reglas que están utilizando las funciones del paquete @code{let} (@code{letsimp}, etc.), a menos que se especifique otro paquete de reglas. A esta variable se le puede asignar el nombre de cualquier paquete de reglas definido por medio de la instrucción @code{let}.

Si se hace la llamada @code{letsimp (expr, rule_pkg_name)}, el paquete de reglas @code{rule_pkg_name} será utilizado únicamente para esa llamada y el valor de @code{current_let_rule_package} no cambia.

@end defvr

@defvr {Variable opcional} default_let_rule_package
@c DEFAULT BINDING OF default_let_rule_package IS default_let_rule_package (BOUND TO ITSELF)
Valor por defecto: @code{default_let_rule_package}

@c THIS IS SORT OF CONFUSING. PROBABLY NEED TO GIVE MORE DETAIL HERE
La variable @code{default_let_rule_package} es el nombre del paquete de reglas utilizado cuando el usuario no especifica otro explícitamente con @code{let} o cambiando el valor de @code{current_let_rule_package}.

@end defvr

@deffn {Función} defmatch (@var{nombre_prog}, @var{patrón}, @var{x_1}, ..., @var{x_n})
@deffnx {Función} defmatch (@var{progname}, @var{pattern})

Define una función @code{@var{nombre_prog}(@var{expr}, @var{x_1}, ..., @var{x_n})} que analiza si @var{expr} coincide con el @var{patrón}.

El argumento @var{patrón} es una expresión que contiene los
argumentos de patrón @var{x_1}, ..., @var{x_n} y algunas variables de patrón.
Los argumentos de patrón se dan de forma explícita
como argumentos a @code{defmatch}, mientras que las variables de patrón
se declaran mediante la función @code{matchdeclare}.
Cualquier variable no declarada bien como variable patrón en @code{matchdeclare},
bien como argumento patrón en @code{defmatch} se hace coincidir con ella
misma.

El primer argumento de la función definida @var{nombre_prog} es una expresión
a ser comparada con el patrón y los demás argumentos son los argumentos 
que se corresponden con las variables ficticias @var{x_1}, ..., @var{x_n} del patrón.

Si el resultado de la comparación es positivo, @var{nombre_prog} devuelve
una lista de ecuaciones cuyos miembros izquierdos son los argumentos y variables de
patrón, y cuyos miembros derechos son las subexpresiones en las que se han 
producido las coincidencias con patrones. A las variables de patrón, no a los
argumentos, se les asignan las subexpresiones con las que coinciden. Si la 
comparación falla, @var{nombre_prog} devuelve @code{false}.  

Un patrón literal, es decir, que no contiene ni argumentos ni variables de patrón,
devuelve @code{true} en caso de coincidencia.



A literal pattern
(that is, a pattern which contains neither pattern arguments nor pattern variables)
returns @code{true} if the match succeeds.

Véase también @code{matchdeclare}, @code{defrule}, @code{tellsimp} y @code{tellsimpafter}.

Ejemplos:

Define una función @code{linearp(expr, x)} que comprueba si
@code{expr} es de la forma @code{a*x + b}, donde
ni @code{a} ni @code{b} contienen a @code{x} y @code{a} es no nulo.
La función definida reconoce expresiones lineales respecto de
cualquier variable, pues el argumento de patrón @code{x} es
pasado a @code{defmatch}.

@c ===beg===
@c matchdeclare (a, lambda ([e],e#0 and freeof(x, e)),
@c               b, 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

Define una función @code{linearp(expr)} que comprueba si
@code{expr} es de la forma @code{a*x + b}, donde
ni @code{a} ni @code{b} contienen a @code{x} y @code{a} es no nulo.
La función definida sólo reconoce expresiones lineales
únicamente respecto de @code{x}, pues no se le pasa a @code{defmatch}
nigún argumento de patrón

@c ===beg===
@c matchdeclare (a, lambda ([e], e#0 and freeof(x, e)),
@c               b, 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

Define una función @code{checklimits(expr)} que comprueba si
@code{expr} es una integral definida.

@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

@end deffn

@deffn {Función} defrule (@var{nombre_regla}, @var{patrón}, @var{reemplazamiento})

Define y da nombre a una regla de reemplazamiento para el patrón dado. Si la regla @var{nombre_regla} es aplicada a una expresión (por @code{apply1}, @code{applyb1} o @code{apply2}), cada subexpresión que coincida con el patrón será reemplazada por el contenido de @var{reemplazamiento}.

Las propias reglas pueden ser tratadas como funciones que transforman una expresión mediante una operación consistente en la búsqueda de una coincidencia y posterior aplicación de un reemplazamiento. Si la comparación falla, la función que implementa la regla devuelve @code{false}.


@end deffn

@deffn {Función} disprule (@var{nombre_regla_1}, ..., @var{nombre_regla_n})
@deffnx {Función} disprule (all)

Muestra las reglas de @var{nombre_regla_1}, ..., @var{nombre_regla_n}, tal como son devueltas por @code{defrule}, @code{tellsimp} o @code{tellsimpafter}, o un patrón definido por @code{defmatch}.
Cada regla se muestra con una etiqueta de expresión intermedia (@code{%t}).

La llamada @code{disprule (all)} muestra todas las reglas.

La función @code{disprule} no evalúa sus argumentos y devuelve la lista de etiquetas de expresiones intermedias correspondientes a las reglas mostradas.

Véase también @code{letrules}, que muestra las reglas definidas por @code{let}.

Ejemplos:

@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

@end deffn

@deffn {Función} let (@var{prod}, @var{repl}, @var{predname}, @var{arg_1}, ..., @var{arg_n})
@deffnx {Función} let ([@var{prod}, @var{repl}, @var{predname}, @var{arg_1}, ..., @var{arg_n}], @var{nombre_paquete})

Define una regla de sustitución para @code{letsimp} tal que @var{prod} es sustituido por @var{repl}, donde @var{prod} es un producto de potencias positivas o negativas de los términos siguientes:

@itemize @bullet
@item
Átomos que @code{letsimp} buscará a menos que antes de llamar a @code{letsimp} se utilice la función @code{matchdeclare} para asociar un predicado con el átomo. En este caso @code{letsimp} hará coincidir el átomo con cualquier término del producto que satisfaga el predicado.
@item
Expresiones básicas como @code{sin(x)}, @code{n!}, @code{f(x,y)}, etc.  Como en el caso anterior, @code{letsimp} buscará coincidencias exactas, a menos que se utilice @code{matchdeclare} para asociar un predicado con el argumento de la expresión básica (@code{sin(x)}, @code{n!}, @code{f(x,y)}, ...).
@end itemize

Si se incluye un predicado en la función @code{let} seguido de una lista de argumentos, una coincidencia aceptable  (es decir, una que fuese aceptada si se hubiese omitido el predicado) se aceptará sólo si @code{predname (arg_1', ..., arg_n')} vale @code{true}, donde @var{arg_i'} es el valor coincidente con @var{arg_i}.  El argumento @var{arg_i} puede ser el nombre de cualquier átomo o el argumento de cualquier expresión básica que aparezca en @var{prod}. 
@var{repl} puede ser cualquier expresión racional. @c ONLY RATIONAL -- REALLY ??
Si cualquiera de los átomos o argumentos de @var{prod} aparece en @var{repl} se llevan a cabo las sustituciones correspondientes.

La variable global @code{letrat} controla la simplificación de los cocientes por @code{letsimp}. Cuando @code{letrat} vale  @code{false}, @code{letsimp} simplifica separadamente el numerador y denominador de  @var{expr} y no simplifica el cociente. Sustituciones como que @code{n!/n} se reduzca a @code{(n-1)!} ya no se realizarán. Cuando  @code{letrat} vale  @code{true}, entonces se simplifican el numerador, el denominador y el cociente, en este orden.

Estas funciones de sustitución permiten al usuario trabajar con varios paquetes de reglas al mismo tiempo. Cada paquete de reglas puede contener cierto número de reglas @code{let} que son referenciadas por un nombre dado por el usuario. 
@code{let ([@var{prod}, @var{repl}, @var{predname}, @var{arg_1}, ..., @var{arg_n}], @var{nombre_paquete})} añade la regla  @var{predname} al paquete de reglas  @var{nombre_paquete}. @code{letsimp (@var{expr}, @var{package_name})} aplica las reglas de @var{nombre_paquete}. La llamada @code{letsimp (@var{expr}, @var{nombre_paquete1}, @var{nombre_paquete2}, ...)}
es equivalente a @code{letsimp (@var{expr}, @var{nombre_paquete1})} seguida de @code{letsimp (%, @var{nombre_paquete2})}, ....

@code{current_let_rule_package} es el nombre del paquete de reglas que se está utilizando. A esta variable se le puede asignar el nombre de cualquier paquete de reglas definido mediante el comando @code{let}. Siempre que una de las funciones incluidas en el paquete  @code{let} sean invocadas sin nombre de paquete, se utilizará el paquete cuyo nombre se guarde en @code{current_let_rule_package}. Si se hace una llamada tal como @code{letsimp (@var{expr}, @var{rule_pkg_name})}, el paquete de reglas @var{rule_pkg_name} es utilizado solamente para ese comando @code{letsimp}, sin efectuarse cambios en 
@code{current_let_rule_package}. A menos que se indique otra cosa, @code{current_let_rule_package} toma por defecto el valor de @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

@end deffn

@defvr {Variable opcional} letrat
Valor por defecto: @code{false}

Cuando @code{letrat} vale @code{false}, @code{letsimp} simplifica separadamente el numerador y denominador de una fracción sin simplificar luego el cociente.

Cuando @code{letrat} vale @code{true}, se simplifican el numerador, denominador y cociente, por este orden.

@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

@end defvr

@deffn {Función} letrules ()
@deffnx {Función} letrules (@var{nombre_paquete})

Muestra las reglas de un paquete de reglas. La llamada @code{letrules ()} muestra las reglas del paquete de reglas actual. La llamada @code{letrules (@var{nombre_paquete})} muestra las reglas de @var{nombre_paquete}.

El paquete de reglas actual tiene su nombre almacenado en by @code{current_let_rule_package}. A menos que se indique de otra manera, @code{current_let_rule_package} toma por defecto el valor de @code{default_let_rule_package}.

Véase también @code{disprule}, que muestra las reglas definidas por @code{tellsimp} y @code{tellsimpafter}.

@end deffn

@deffn {Función} letsimp (@var{expr})
@deffnx {Función} letsimp (@var{expr}, @var{nombre_paquete})
@deffnx {Función} letsimp (@var{expr}, @var{nombre_paquete_1}, ..., @var{nombre_paquete_n})

Aplica repetidamente las reglas definidas por @code{let} hasta que no se puedan hacer más cambios en @var{expr}.

La llamada @code{letsimp (@var{expr})} utiliza las reglas de @code{current_let_rule_package}.

La llamada @code{letsimp (@var{expr}, @var{nombre_paquete})} utiliza las reglas de @var{nombre_paquete} sin efectuar cambios en @code{current_let_rule_package}.

La llamada @code{letsimp (@var{expr}, @var{nombre_paquete_1}, ..., @var{nombre_paquete_n})}
es equivalente a @code{letsimp (@var{expr}, @var{nombre_paquete_1}}, seguida de  @code{letsimp (%, @var{nombre_paquete_2})} y así sucesivamente.

@end deffn

@defvr {Variable opcional} let_rule_packages
Valor por defecto: @code{[default_let_rule_package]}

La variable @code{let_rule_packages} guarda una lista con todos los paquetes de reglas definidos por el usuario, junto con el paquete por defecto @code{default_let_rule_package}.

@end defvr

@deffn {Función} matchdeclare (@var{a_1}, @var{pred_1}, ..., @var{a_n}, @var{pred_n})
Asocia un predicado @var{pred_k} con una variable o lista de variables  @var{a_k}, de forma que  @var{a_k} se comparará con expresiones para las cuales el predicado devuelva algo que no sea @code{false}.

Un predicado puede ser el nombre de una función, una expresión lambda, una
llamada a función, una llamada a una expresión lambda sin
el último argumento, @code{true} o @code{all}.
Cualquier expresión se hace coincidir con @code{true} o @code{all}. 

Si el predicado se especifica como una llamada a función o a
una expresión lambda, la expresión a ser analizada es añadida 
a la lista de argumentos, siendo los argumentos evaluados en el 
momento de ser evaluada la comparación. 
En cambio, si el predicado se especifica como un nombre de función
o como una expresión lambda, la expresión a ser analizada será 
su único argumento. No es necesario definir una función de predicado cuando se hace una llamada a @code{matchdeclare}; el predicado no se evalúa hasta que se ensaya  una comparación.

Un predicado puede devolver tanto una expresión booleana,
como @code{true} o @code{false}.
Las expresiones booleanas se evalúan con @code{is} dentro
de la regla, por lo que no es necesario llamar a @code{is}
desde dentro del predicado.

Si una expresión satisface un predicado, se asigna a la variable de comparación la expresión, excepto cuando las variables de comparación son operandos de sumas @code{+} o multiplicaciones @code{*}. Solamente las sumas y multiplicaciones son tratadas de forma especial; los demás operadores n-arios (tanto los del sistema como los definidos por el usuario) son tratados como funciones ordinarias.

En el caso de sumas y multiplicaciones, a la variable de comparación se le puede asignar una expresión simple que satisfaga el predicado de comparación, o una suma o producto, respectivamente, de tales expresiones. Los predicados son evaluados en el orden en el que sus variables asociadas aparecen en el patrón de comparación, y un término que satisfaga más de un predicado es tomado por el primer predicado que satisfaga. Cada predicado se compara con todos los operandos de la suma o producto antes de ser evaluado el siguiente predicado. Además, si 0 o 1, respectivamente, satisface un predicado de comparación, y no hay otros términos que lo satisfagan, se asignará el 0 o 1 a la variable de comparación asociada al predicado.

El algoritmo para procesar patrones de suma y multiplicación hace que los resultados de algunas comparaciones dependan del orden de los términos en el patrón de comparación y en la expresión a ser comparada. Sin embargo, si todos los predicados de comparación son mutuamente excluyentes, el resultado de la comparación no depende para nada de la ordenación, puesto que un predicado de comparación no puede aceptar términos aceptados por otros predicados.

Invocando @code{matchdeclare} con una variable @var{a} como argumento cambia la propiedad de @code{matchdeclare} para  @var{a}, si ya había una declarada; solamente el @code{matchdeclare} más reciente está activo cuando se define una regla. Cambios posteriores en la propiedad de @code{matchdeclare} (via @code{matchdeclare} o @code{remove}) no afectan a las reglas existentes.

@code{propvars (matchdeclare)} devuelve la lista de todas las variables para las cuales hay una propiedad de @code{matchdeclare}. La llamada @code{printprops (@var{a}, matchdeclare)} devuelve el predicado para la variable @code{a}.
La llamada @code{printprops (all, matchdeclare)} devuelve la lista de predicados de todas las variables de @code{matchdeclare}. La llamada @code{remove (@var{a}, matchdeclare)} borra la propiedad @code{matchdeclare} de @var{a}.

Las funciones @code{defmatch}, @code{defrule}, @code{tellsimp}, @code{tellsimpafter} y @code{let} construyen reglas que analizan expresiones mediante patrones.

@code{matchdeclare} no evalúa sus argumentos y siempre devuelve @code{done}.

Ejemplos:

Un predicado puede ser el nombre de una función, una expresión lambda, una
llamada a función, una llamada a una expresión lambda sin
el último argumento, @code{true} o @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

Si una expresión satisface un predicado, se asigna a la variable de comparación la expresión.

@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

En el caso de sumas y multiplicaciones, a la variable de comparación se le puede asignar una expresión simple que satisfaga el predicado de comparación, o una suma o producto, respectivamente, de tales expresiones. 

@c ===beg===
@c matchdeclare (aa, atom, bb, lambda ([x], not atom(x)));
@c defrule (r1, aa + bb,
@c          ["all atoms" = aa, "all nonatoms" = bb]);
@c r1 (8 + a*b + sin(x));
@c defrule (r2, aa * bb,
@c          ["all atoms" = aa, "all nonatoms" = 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

@end deffn



@defvr {Variable opcional} maxapplydepth
Valor por defecto: 10000

La variable @code{maxapplydepth} es la máxima profundidad a la que van a introducirse @code{apply1} y  @code{apply2}.

@end defvr


@defvr {Variable opcional} maxapplyheight
Valor por defecto: 10000

La variable @code{maxapplyheight} es la m2'axima altura a la que escalará @code{applyb1} antes de detenerse.

@end defvr


@deffn {Función} remlet (@var{prod}, @var{nombre})
@deffnx {Función} remlet ()
@deffnx {Función} remlet (all)
@deffnx {Función} remlet (all, @var{nombre})

Elimina la última regla de sustitución @var{prod} --> repl que haya sido definida por la función @code{let}. Si se suministar el nombre la regla será borrada del paquete con ese mismo nombre.

Las llamadas @code{remlet()} y @code{remlet(all)} eliminan todas las reglas de sustitución del paquete de reglas actual. Si se suministra el nombre de un paquete de reglas, como en @code{remlet (all, @var{nombre})}, el paquete de reglas con ese  @var{nombre} es también eliminado.

Si es necesario cambiar una sustitución haciendo uso de la misma producción, no es necesario llamar a  @code{remlet}, simplemente redefínase la sustitución utilizando la misma producción con la función  @code{let} junto con el nuevo reemplazamiento y/o nombre de predicado. De ser llamado nuevamente @code{remlet (@var{prod})} la sustitución original sería recuperada.

Véase también @code{remrule}, que elimina una regla definida por  @code{tellsimp} o @code{tellsimpafter}.

@end deffn

@deffn {Función} remrule (@var{op}, @var{nombre_regla})
@deffnx {Función} remrule (@var{op}, all)

Elimina las reglas previamente definidas por @code{tellsimp} o @code{tellsimpafter}.

La llamada @code{remrule (@var{op}, @var{nombre_regla})} elimina la regla de nombre  @var{nombre_regla} del operador @var{op}.

Independientemente de que  @var{op} sea un operador propio de Maxima o haya sido definido por el usario (como los establecidos por @code{infix}, @code{prefix}, etc.), tanto @var{op} como @var{rulename} deben ir encerrados entre comillas dobles.

La llamada @code{remrule (@var{function}, all)} borra todas las reglas para el operador @var{op}.

Véase también @code{remlet}, que elimina una regla definida mediante @code{let}.

Ejemplos:
         
@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

@end deffn

@deffn {Función} tellsimp (@var{patrón}, @var{reemplazamiento})

La función @code{tellsimp} es similar a  @code{tellsimpafter} pero coloca nueva información antes que la antigua, de manera que se aplica antes que las reglas de simplificación de Maxima.

La función @code{tellsimp} se utiliza cuando es importante utilizar la expresión antes de que el simplificador opere sobre ella; por ejemplo, cuando el simplificador ya "sabe" algo sobre una expresión, pero lo que devuelve no es lo que quiere el usuario. En cambio, cuando  el simplificador ya "sabe" algo sobre una expresión pero lo que devuelve no es lo suficiente para el usuario, entonces éste podrá estar interesado en utilizar @code{tellsimpafter}.

El patrón no puede ser una suma, ni un producto, ni una variable ni un número.

@code{rules} es la lista de reglas definidas por
@code{defrule}, @code{defmatch}, @code{tellsimp} y @code{tellsimpafter}.

Ejemplos:

@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

@end deffn

@deffn {Función} tellsimpafter (@var{patrón}, @var{reemplazamiento})

Define una regla de simplificación que el simplificador aplicará después de las reglas de simplificación propias de de Maxima. El @var{patrón} es una expresión que contiene variables de patrón (declaradas por @code{matchdeclare}) junto con otros átomos y operadores. El contenido de @var{reemplazamiento} sustituye una expresión que coincida con el patrón; a las variables de patrón en @var{reemplazamiento} se les asignan los valores coincidentes en la expresión.

El @var{patrón} puede ser una expresión no atómica en la que el operador principal no sea una variable de patrón; la regla de simplificación se asocia con el operador principal. Los nombres de las funciones (con una excepción que se indica más abajo), listas y arrays pueden aparecer en el @var{patrón} como operador principal sólo como literales (no variables de patrones); esto excluye expresiones como  @code{aa(x)} y @code{bb[y]}, si tanto @code{aa} como @code{bb} son patrones de variables. Nombres de funciones, listas y arrays que sean variables de patrón pueden aparecer como operadores que no sean el operador principal de  @var{patrón}.

Hay una excepción a la regla indicada más arriba concerniente a los nombres de funciones. El nombre de una función subindicada en una expresión tal como @code{aa[x](y)} puede ser una variable de patrón porque el operador principal no es  @code{aa} sino el átomo de Lisp  @code{mqapply}. Esta es una consecuencia de la representación de expresiones que contienen funciones subindicadas.

Las reglas de simplificación se aplican tras las evaluaciones (a menos que se supriman con el apóstrofo o la variable @code{noeval}). Las reglas establecidas por @code{tellsimpafter} se aplican en el orden en que han sido definidas y después de las reglas propias de Maxima. Las reglas se aplican de abajo arriba, esto es, se aplican primero a las subexpresiones antes que a toda la expresión. Puede ser necesario simplificar repetidamente un resultado (por ejemplo, mediante el operador de doble comilla simple @code{'@w{}'} o la variable @code{infeval}) para asegurar que se aplican todas las reglas.

Las variables de patrón se tratan como variables locales en las reglas de simplificación. Una vez definida una regla, el valor de una variable de patrón no afecta a la regla, ni se ve influenciada poe ésta. Una asignación a una variable de patrón que resulta de la aplicación exitosa de una regla no afecta a la asignación actual de la variable de patrón. Sin embargo, como cualquier otro átomo de Maxima, las propiedades de las variables de patrón (tal como se definen con @code{put} y sus funciones relacionadas) son globales.

La regla construida por  @code{tellsimpafter} es nombrada detrás del operador principal de @var{patrón}. Reglas para operadores de Maxima y operadores definidos por el usuario con @code{infix}, @code{prefix}, @code{postfix}, @code{matchfix} y @code{nofix}, tienen nombres que son cadenas alfanuméricas de Maxima. Reglas para otras funciones tienen nombres que son identificadores ordinarios de Maxima.

El tratamiento de formas nominales y verbales es hasta cierto punto confuso. Si se define una regla para una forma nominal (o verbal)  y ya existe una regla para la correspondiente forma verbal (o nominal), la regla recién definida se aplica a ambas formas (nominal y verbal). Si no existe regla para una forma verbal (o nominal) la regla recién definida se aplica únicamente a la forma nominal (o verbal).

La regla construida por  @code{tellsimpafter} es una típica función de Lisp. Si el nombre de la regla es @code{$foorule1}, la sentencia @code{:lisp (trace $foorule1)} hace una traza de la función y  @code{:lisp (symbol-function '$foorule1)} muestra su definición.

La función @code{tellsimpafter} no evalúa sus argumentos y devuelve la lista de reglas para el operador principal de  @var{patrón}, incluida la regla recién establecida.

Véanse también @code{matchdeclare}, @code{defmatch}, @code{defrule}, @code{tellsimp}, @code{let},
@code{kill}, @code{remrule} y @code{clear_rules}.

Ejemplos:

@var{pattern} puede ser cualquier expresión no atómica en la que el operador principal no sea una variable de patrón.

@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

Las reglas se aplican en el orden en que se definen. Si dos reglas coinciden con una expresión, se aplica aquélla que haya sido definida en primer lugar.

@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

Las variables de patrón se tratan como variables locales en las reglas de simplificación.
(Compárese con @code{defmatch}, que trata las variables de patrón como globales.)

@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

Como cualquier otro átomo, las propiedades de las variables de patrón son globales, incluso cuando sus valores sean locales. En este ejemplo se declara una propiedad de asignación a treavés de  @code{define_variable}. Esta es una propiedad del átomo  @code{bb} en todo Maxima.

@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

Las reglas se nombran después de los operadores principales. Los nombres de reglas tanto para las funciones de Maxima como para las definidas por el usuario son cadenas alfanuméricas, mientras que los nombres de las otras funciones son identificadores típicos.

@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) [trigrule0, trigrule1, trigrule2, trigrule3, trigrule4, 
htrigrule1, htrigrule2, htrigrule3, htrigrule4, foorule1, 
foorule2, foorule3, +rule1, *rule1, ^rule1]
(%i8) foorule_name: first (%o1);
(%o8)                       foorule1
(%i9) plusrule_name: first (%o4);
(%o9)                        +rule1
(%i10) [?mstringp (foorule_name), symbolp (foorule_name)];
(%o10)                    [false, true]
(%i11) [?mstringp (plusrule_name), symbolp (plusrule_name)];
(%o11)                    [true, true]
(%i12) remrule (foo, foorule1);
(%o12)                         foo
(%i13) remrule ("^", "^rule1");
(%o13)                          ^
@end example

Un ejemplo de producto anticonmutativo.

@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

@end deffn

@deffn {Función} clear_rules ()

Ejecuta @code{kill (rules)} y después inicializa el siguiente número de regla a 1 para la adición @code{+}, multiplicación @code{*} y exponenciación @code{^}.

@end deffn


































