@c English version: 2012-08-22
@menu
* Introducción a polinomios ortogonales::
* Funciones y variables para polinomios ortogonales::
@end menu

@node Introducción a polinomios ortogonales, Funciones y variables para polinomios ortogonales, orthopoly, orthopoly
@section Introducción a polinomios ortogonales

El paquete @code{orthopoly} contiene funciones para la evaluación
simbólica y numérica de diversos tipos de polinomios ortogonales, como
los de Chebyshev, Laguerre, Hermite, Jacobi, Legendre y ultraesféricos 
(Gegenbauer). Además, @code{orthopoly} soporta las funciones esféricas
de Bessel, Hankel y armónicas.

Referencias:
@itemize @bullet
@item
Abramowitz y Stegun, @i{Handbook of Mathematical Functions},
(1972, décima reimpresión, capítulo 22)

@item
Gradshteyn y Ryzhik, @i{Table of Integrals, Series y  Products}, (1980, edición
corregida y ampliada)

@item
Eugen Merzbacher, @i{Quantum Mechanics}, (1970, segunda edición)

@end itemize

El paquete @code{orthopoly}, junto con su documentación, fue escrito por 
Barton Willis de la Universidad de Nebraska en Kearney. El paquete se
distribuye con la licencia GNU General Public License (GPL).


@subsection Iniciándose con orthopoly

@code{load (orthopoly)} carga el paquete @code{orthopoly}.

Para obtener el polinomio de Legendre de tercer orden,

@c ===beg===
@c legendre_p (3, x);
@c ===end===
@example
(%i1) legendre_p (3, x);
                      3             2
             5 (1 - x)    15 (1 - x)
(%o1)      - ---------- + ----------- - 6 (1 - x) + 1
                 2             2
@end example

Para expresarlo como una suma de potencias de @var{x}, aplíquese
@var{ratsimp} o @var{rat} al resultado.

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c [ratsimp (%), rat (%)];
@c ===end===
@example
(%i2) [ratsimp (%), rat (%)];
                        3           3
                     5 x  - 3 x  5 x  - 3 x
(%o2)/R/            [----------, ----------]
                         2           2
@end example

De forma alternativa, conviértase el segundo argumento de to @code{legendre_p}
(su variable  ``principal'') a una expresión racional canónica 
(canonical rational expression, CRE)).

@c ===beg===
@c legendre_p (3, rat (x));
@c ===end===
@example
(%i1) legendre_p (3, rat (x));
                              3
                           5 x  - 3 x
(%o1)/R/                   ----------
                               2
@end example

Para la evaluación numérica,  @code{orthopoly} hace uso del análisis
de error de ejecución para estimar una cota superior del error. Por ejemplo,

@c ===beg===
@c jacobi_p (150, 2, 3, 0.2);
@c ===end===
@example
(%i1) jacobi_p (150, 2, 3, 0.2);
(%o1) interval(- 0.062017037936715, 1.533267919277521E-11)
@end example

Los intervalos tienen la forma @code{interval (@var{c}, @var{r})}, donde
@var{c} es el centro y @var{r} el radio del intervalo. Puesto que Maxima
no soporta aritmética de intervalos, en algunas situaciones, como en los 
gráficos, puede ser necesario ignorar el error y utilizar el centro del
intervalo. Para conseguirlo conviene asignar a la variable 
@code{orthopoly_returns_intervals} el valor @code{false}.

@c ===beg===
@c orthopoly_returns_intervals : false;
@c jacobi_p (150, 2, 3, 0.2);
@c ===end===
@example
(%i1) orthopoly_returns_intervals : false;
(%o1)                         false
(%i2) jacobi_p (150, 2, 3, 0.2);
(%o2)                  - 0.062017037936715
@end example

Véase la sección @i{Evaluación numérica} para más información.

La mayor parte de las funciones de @code{orthopoly} tienen una propiedad
@code{gradef}; así,

@c ===beg===
@c diff (hermite (n, x), x);
@c diff (gen_laguerre (n, a, x), x);
@c ===end===
@example
(%i1) diff (hermite (n, x), x);
(%o1)                     2 n H     (x)
                               n - 1
(%i2) diff (gen_laguerre (n, a, x), x);
              (a)               (a)
           n L   (x) - (n + a) L     (x) unit_step(n)
              n                 n - 1
(%o2)      ------------------------------------------
                               x
@end example

La función @code{unit_step} del segundo ejemplo evita el error que
aparecería al evaluar la expresión con @var{n} igual a 0.

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c ev (%, n = 0);
@c ===end===
@example
(%i3) ev (%, n = 0);
(%o3)                           0
@end example

La propiedad "gradef" sólo se aplica a la variable principal; derivadas 
respecto de las otras variables darán lugar normalmente a mensajes de 
error; por ejemplo,

@c ===beg===
@c diff (hermite (n, x), x);
@c diff (hermite (n, x), n);
@c ===end===
@example
(%i1) diff (hermite (n, x), x);
(%o1)                     2 n H     (x)
                               n - 1
(%i2) diff (hermite (n, x), n);

Maxima doesn't know the derivative of hermite with 
respect the first argument
 -- an error.  Quitting.  To debug this try debugmode(true);
@end example

Generalmente, las funciones de @code{orthopoly} se distribuyen sobre listas y
matrices. Al objeto de que la evaluación se realice completamente, las variables
opcionales @code{doallmxops} y @code{listarith} deben valer ambas @code{true},
que es el valor por defecto. Para ilustrar la distribución sobre matrices 
sirve el siguiente ejemplo

@c ===beg===
@c hermite (2, x);
@c m : matrix ([0, x], [y, 0]);
@c hermite (2, m);
@c ===end===
@example
(%i1) hermite (2, x);
                                     2
(%o1)                    - 2 (1 - 2 x )
(%i2) m : matrix ([0, x], [y, 0]);
                            [ 0  x ]
(%o2)                       [      ]
                            [ y  0 ]
(%i3) hermite (2, m);
               [                             2  ]
               [      - 2        - 2 (1 - 2 x ) ]
(%o3)          [                                ]
               [             2                  ]
               [ - 2 (1 - 2 y )       - 2       ]
@end example

En el segundo ejemplo, el elemento @code{i, j}-ésimo es
@code{hermite (2, m[i,j])}, que no es lo mismo que calcular
@code{-2 + 4 m . m}, según se ve en el siguiente ejemplo.

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c -2 * matrix ([1, 0], [0, 1]) + 4 * m . m;
@c ===end===
@example
(%i4) -2 * matrix ([1, 0], [0, 1]) + 4 * m . m;
                    [ 4 x y - 2      0     ]
(%o4)               [                      ]
                    [     0      4 x y - 2 ]
@end example

Si se evalúa una función en un punto fuera de su dominio de definición,
generalmente @code{orthopoly} devolverá la función sin evaluar. Por ejemplo,

@c ===beg===
@c legendre_p (2/3, x);
@c ===end===
@example
(%i1) legendre_p (2/3, x);
(%o1)                        P   (x)
                              2/3
@end example

@code{orthopoly} da soporte a la traducción de expresiones al formato TeX y
la representación bidimensional en el terminal.

@c ===beg===
@c spherical_harmonic (l, m, theta, phi);
@c tex (%);
@c jacobi_p (n, a, a - b, x/2);
@c tex (%);
@c ===end===
@example
(%i1) spherical_harmonic (l, m, theta, phi);
                          m
(%o1)                    Y (theta, phi)
                          l
(%i2) tex (%);
$$Y_@{l@}^@{m@}\left(\vartheta,\varphi\right)$$
(%o2)                         false
(%i3) jacobi_p (n, a, a - b, x/2);
                          (a, a - b) x
(%o3)                    P          (-)
                          n          2
(%i4) tex (%);
$$P_@{n@}^@{\left(a,a-b\right)@}\left(@{@{x@}\over@{2@}@}\right)$$
(%o4)                         false
@end example

@subsection Limitaciones

Cuando una expresión contenga varios polinomios ortogonales
con órdenes simbólicos, es posible que aunque la expresión sea
nula, Maxima sea incapaz de simplificarla a cero, por lo que si se
divide por esta cantidad, aparecerán problemas. Por ejemplo, la
siguiente expressión se anula para enteros @var{n} mayores que
1, no pudiendo Maxima reducirla a cero.

@c ===beg===
@c (2*n - 1) * legendre_p (n - 1, x) * x - n * legendre_p (n, x)
@c         + (1 - n) * legendre_p (n - 2, x);
@c ===end===
@example
(%i1) (2*n - 1) * legendre_p (n - 1, x) * x - n * legendre_p (n, x)
                + (1 - n) * legendre_p (n - 2, x);
(%o1)  (2 n - 1) P     (x) x - n P (x) + (1 - n) P     (x)
                  n - 1           n               n - 2
@end example

Para un valor específico de @var{n} se puede
reducir la expresión a cero.

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c ev (% ,n = 10, ratsimp);
@c ===end===
@example
(%i2) ev (% ,n = 10, ratsimp);
(%o2)                           0
@end example

Generalmente, la forma polinomial de un polinomio ortogonal no es la más
apropiada para su evaluación numérica. Aquí un ejemplo.

@c ===beg===
@c p : jacobi_p (100, 2, 3, x)$
@c subst (0.2, x, p);
@c jacobi_p (100, 2, 3, 0.2);
@c float(jacobi_p (100, 2, 3, 2/10));
@c ===end===
@example 
(%i1) p : jacobi_p (100, 2, 3, x)$
(%i2) subst (0.2, x, p);
(%o2)                3.4442767023833592E+35
(%i3) jacobi_p (100, 2, 3, 0.2);
(%o3)  interval(0.18413609135169, 6.8990300925815987E-12)
(%i4) float(jacobi_p (100, 2, 3, 2/10));
(%o4)                   0.18413609135169
@end example

Este resultado se puede mejorar expandiendo el polinomio y evaluando
a continuación, lo que da una aproximación mejor.
@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c p : expand (p)$
@c subst (0.2, x, p);
@c ===end===
@example
(%i5) p : expand(p)$
(%i6) subst (0.2, x, p);
(%o6) 0.18413609766122982
@end example

Sin embargo esto no vale como regla general; la expansión del
polinomio no siempre da como resultado una expresión más fácil
de evaluar numéricamente. Sin duda, la mejor manera de hacer la
evaluación numérica consiste en hacer que uno o más de los argumentos
de la función sean decimales en coma flotante; de esta forma se utilizarán
algoritmos decimales especializados para hacer la evaluación.

La función @code{float} de Maxima trabaja de forma indiscriminada; si se aplica
@code{float} a una expresión que contenga un polinomio ortogonal con el grado u orden
simbólico, éstos se pueden transformar en decimales y la expresión no ser
evaluada de forma completa. Considérese

@c ===beg===
@c assoc_legendre_p (n, 1, x);
@c float (%);
@c ev (%, n=2, x=0.9);
@c ===end===
@example
(%i1) assoc_legendre_p (n, 1, x);
                               1
(%o1)                         P (x)
                               n
(%i2) float (%);
                              1.0
(%o2)                        P   (x)
                              n
(%i3) ev (%, n=2, x=0.9);
                             1.0
(%o3)                       P   (0.9)
                             2
@end example

La expresión en @code{(%o3)} no da como resultado un decimal en coma flotante; 
@code{orthopoly} no reconoce decimales donde espera que haya enteros. De forma semejante,
la evaluación numérica de la función @code{pochhammer} para órdenes que
excedan @code{pochhammer_max_index} puede ser problemática; considérese

@c ===beg===
@c x :  pochhammer (1, 10), pochhammer_max_index : 5;
@c ===end===
@example
(%i1) x :  pochhammer (1, 10), pochhammer_max_index : 5;
(%o1)                         (1)
                                 10
@end example

Aplicando @code{float} no da para @var{x} un valor decimal

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c float (x);
@c ===end===
@example
(%i2) float (x);
(%o2)                       (1.0)
                                 10.0
@end example

A fin de evaluar @var{x} como decimal, es necesario asignar a 
@code{pochhammer_max_index} en valor 11 o mayor y aplicar 
@code{float} a @var{x}.

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c float (x), pochhammer_max_index : 11;
@c ===end===
@example
(%i3) float (x), pochhammer_max_index : 11;
(%o3)                       3628800.0
@end example

El valor por defecto de @code{pochhammer_max_index} es 100;
cámbiese este valor tras cargar el paquete @code{orthopoly}.

Por último, téngase en cuenta que las referencias bibliográficas
no coinciden a la hora de definir los polinomios ortogonales; en 
@code{orthopoly} se han utilizado normalmente las convenciones seguidas
por Abramowitz y Stegun.

Cuando se sospeche de un fallo en @code{orthopoly}, compruébense algunos
casos especiales a fin de determinar si las definiciones de las que el
usuario parte coinciden con las utilizadas por el paquete @code{orthopoly}.
A veces las definiciones difieren por un factor de normalización; algunos
autores utilizan versiones que hacen que las familias sean ortogonales
en otros intervalos diferentes de @math{(-1, 1)}. Así por
ejemplo, para definir un polinomio de Legendre ortogonal en @math{(0, 1)}
defínase

@c ===beg===
@c shifted_legendre_p (n, x) := legendre_p (n, 2*x - 1)$
@c shifted_legendre_p (2, rat (x));
@c legendre_p (2, rat (x));
@c ===end===
@example
(%i1) shifted_legendre_p (n, x) := legendre_p (n, 2*x - 1)$

(%i2) shifted_legendre_p (2, rat (x));
                            2
(%o2)/R/                 6 x  - 6 x + 1
(%i3) legendre_p (2, rat (x));
                               2
                            3 x  - 1
(%o3)/R/                    --------
                               2
@end example

@anchor{Evaluación numérica}
@subsection Evaluación numérica

La mayor parte de las funciones de @code{orthopoly} realizan análisis de
errores en tiempo de ejecución para estimar el error en la evaluación
decimal, a excepción de las funciones esféricas de Bessel y los 
polinomios asociados de Legendre de segunda especie. Para la 
evaluación numérica, las funciones esféricas de Bessel hacen uso
de funciones SLATEC. No se lleva a cabo ningún método especial de
evaluación numérica para los polinomios asociados de Legendre de 
segunda especie.

Es posible, aunque improbable, que el error obtenido en las evaluaciones 
numéricas exceda al error estimado.


Los intervalos tienen la forma @code{interval (@var{c}, @var{r})},
siendo @var{c} el centro del intervalo y @var{r} su radio. El
centro del intervalo puede ser un número complejo, pero el radio
será siempre un número real positivo.

He aquí un ejemplo:

@c ===beg===
@c fpprec : 50$
@c y0 : jacobi_p (100, 2, 3, 0.2);
@c y1 : bfloat (jacobi_p (100, 2, 3, 1/5));
@c ===end===
@example
(%i1) fpprec : 50$
(%i2) y0 : jacobi_p (100, 2, 3, 0.2);
(%o2) interval(0.1841360913516871, 6.8990300925815987E-12)
(%i3) y1 : bfloat (jacobi_p (100, 2, 3, 1/5));
(%o3) 1.8413609135168563091370224958913493690868904463668b-1
@end example

Se comprueba que el error es menor que el estimado

@c CONTINUING PREVIOUS EXAMPLE HERE
@c ===beg===
@c is (abs (part (y0, 1) - y1) < part (y0, 2));
@c ===end===
@example
(%i4) is (abs (part (y0, 1) - y1) < part (y0, 2));
(%o4)                         true
@end example

En este ejemplo el error estimado es una cota superior para el error
verdadero.

Maxima no da soporte a la aritmética de intervalos.

@c ===beg===
@c legendre_p (7, 0.1) + legendre_p (8, 0.1);
@c ===end===
@example
(%i1) legendre_p (7, 0.1) + legendre_p (8, 0.1);
(%o1) interval(0.18032072148437508, 3.1477135311021797E-15)
        + interval(- 0.19949294375000004, 3.3769353084291579E-15)
@end example

El usuario puede definir operadores aritméticos para los intervalos.
Para definir la suma de intervalos se puede hacer

@c ===beg===
@c infix ("@+")$
@c "@+"(x,y) := interval (part (x, 1) + part (y, 1),
@c                        part (x, 2) + part (y, 2))$
@c legendre_p (7, 0.1) @+ legendre_p (8, 0.1);
@c ===end===
@example
(%i1) infix ("@@+")$

(%i2) "@@+"(x,y) := interval (part (x, 1) + part (y, 1), 
                              part (x, 2) + part (y, 2))$
(%i3) legendre_p (7, 0.1) @@+ legendre_p (8, 0.1);
(%o3) interval(- 0.019172222265624955, 6.5246488395313372E-15)
@end example

Las rutinas especiales para cálculo numérico son llamadas cuando
los argumentos son complejos. Por ejemplo,

@c ===beg===
@c legendre_p (10, 2 + 3.0*%i);
@c ===end===
@example
(%i1) legendre_p (10, 2 + 3.0*%i);
(%o1) interval(- 3.876378825E+7 %i - 6.0787748E+7, 
                                           1.2089173052721777E-6)
@end example

Compárese con el valor verdadero.

@c ===beg===
@c float (expand (legendre_p (10, 2 + 3*%i)));
@c ===end===
@example
(%i1) float (expand (legendre_p (10, 2 + 3*%i)));
(%o1)          - 3.876378825E+7 %i - 6.0787748E+7
@end example

Además, cuando los argumentos son números decimales grandes 
(@i{big floats}), se realizan llamadas a las rutinas numéricas 
especiales; sin embargo, los decimales grandes se convierten 
previamente a doble precisión y de este tipo serán también
los resultados.

@c ===beg===
@c ultraspherical (150, 0.5b0, 0.9b0);
@c ===end===
@example
(%i1) ultraspherical (150, 0.5b0, 0.9b0);
(%o1) interval(- 0.043009481257265, 3.3750051301228864E-14)
@end example

@subsection Gráficos y orthopoly

Para representar gráficamente expresiones que contengan polinomios
ortogonales se deben hacer dos cosas:
@enumerate
@item 
Asignar a la variable opcional @code{orthopoly_returns_intervals} el valor @code{false},
@item
Comentar (con apóstrofo) las llamadas a las funciones de @code{orthopoly}.
@end enumerate
Si las llamadas a las funciones no se comentan, Maxima las evalúa a 
polinomios antes de hacer el gráfico, por lo que el código especializado
en el cálculo numérico no es llamado. Aquí hay un ejemplo 
de cómo se debe hacer para representar gráficamente una expresión que
contiene un polinomio de Legendre:

@c ===beg===
@c plot2d ('(legendre_p (5, x)), [x, 0, 1]),
@c orthopoly_returns_intervals : false;
@c ===end===
@example
(%i1) plot2d ('(legendre_p (5, x)), [x, 0, 1]),
      orthopoly_returns_intervals : false;
(%o1)
@end example

@ifnotinfo
@image{../figures/orthopoly1,8cm}
@end ifnotinfo

La expresión @code{legendre_p (5, x)} se comenta @i{completamente}, que no es 
lo mismo que comentar el nombre de la función, como en
@code{'legendre_p (5, @var{x})}.

@subsection Miscelánea de funciones

El paquete @code{orthopoly} define el símbolo de Pochhammer y
la función de escalón unidad en sentencias gradef.

Para convertir los símbolos de Pochhammer en cocientes o
funciones gamma, hágase uso de @code{makegamma}.

@c ===beg===
@c makegamma (pochhammer (x, n));
@c makegamma (pochhammer (1/2, 1/2));
@c ===end===
@example
(%i1) makegamma (pochhammer (x, n));
                          gamma(x + n)
(%o1)                     ------------
                            gamma(x)
(%i2) makegamma (pochhammer (1/2, 1/2));
                                1
(%o2)                       ---------
                            sqrt(%pi)
@end example

Las derivadas del símbolo de Pochhammer se dan en
términos de la función @code{psi}.

@c ===beg===
@c diff (pochhammer (x, n), x);
@c diff (pochhammer (x, n), n);
@c ===end===
@example
(%i1) diff (pochhammer (x, n), x);
(%o1)             (x)  (psi (x + n) - psi (x))
                     n     0             0
(%i2) diff (pochhammer (x, n), n);
(%o2)                   (x)  psi (x + n)
                           n    0
@end example

Es necesario tener cuidado con la expresión en @code{(%o1)}, pues la diferencia
de las funciones @code{psi} tiene polos cuando @code{@var{x} = -1, -2, .., -@var{n}}.
Estos polos se cancelan con factores de @code{pochhammer (@var{x}, @var{n})}
haciendo que la derivada sea un polinomio de grado @code{@var{n} - 1} si @var{n}
es entero positivo.

El símbolo de Pochhammer se define para órdenes negativos a
través de su representación como cociente de funciones gamma. Considérese

@c ===beg===
@c q : makegamma (pochhammer (x, n));
@c sublis ([x=11/3, n= -6], q);
@c ===end===
@example
(%i1) q : makegamma (pochhammer (x, n));
                          gamma(x + n)
(%o1)                     ------------
                            gamma(x)
(%i2) sublis ([x=11/3, n= -6], q);
                               729
(%o2)                        - ----
                               2240
@end example

De forma alternativa, es posible llegar a este resultado directamente.

@c ===beg===
@c pochhammer (11/3, -6);
@c ===end===
@example
(%i1) pochhammer (11/3, -6);
                               729
(%o1)                        - ----
                               2240
@end example

La función de escalón unidad es continua por la izquierda; así,

@c ===beg===
@c [unit_step (-1/10), unit_step (0), unit_step (1/10)];
@c ===end===
@example
(%i1) [unit_step (-1/10), unit_step (0), unit_step (1/10)];
(%o1)                       [0, 0, 1]
@end example

En caso de ser necesaria una función escalón unidad que no sea
continua ni por la izquierda ni por la derecha en el origen, se puede definir
haciendo uso de @code{signum}; por ejemplo,

@c ===beg===
@c xunit_step (x) := (1 + signum (x))/2$
@c [xunit_step (-1/10), xunit_step (0), xunit_step (1/10)];
@c ===end===
@example
(%i1) xunit_step (x) := (1 + signum (x))/2$

(%i2) [xunit_step (-1/10), xunit_step (0), xunit_step (1/10)];
                                1
(%o2)                       [0, -, 1]
                                2
@end example

No se debe redefinir la función @code{unit_step}, ya que parte del
código de @code{orthopoly} requiere que la función escalón sea
continua por la izquierda.

@subsection Algoritmos

En general, el paquete @code{orthopoly} gestiona la evaluación
simbólica a través de la representación hipergeométrica de 
los polinomios ortogonales. Las funciones hipergeométricas se
evalúan utilizando las funciones (no documentadas) @code{hypergeo11} 
y @code{hypergeo21}. Excepciones son las funciones de Bessel de
índice semi-entero y las funciones asociadas de 
Legendre de segunda especie; las funciones de Bessel de índice
semi-entero se evalúan 
utilizando una representación explícita, mientras que
la función asociada de Legendre de segunda especie se evalúa 
recursivamente.

En cuanto a la evaluación numérica, la mayor parte de las funciones
se convierten a su forma hipergeométrica, evaluándolas mediante recursión.
Además, las excepciones son las funciones de Bessel de índice
semi-entero y las funciones asociadas de Legendre de segunda especie.
Las funciones de Bessel de índice semi-entero se evalúan 
numéricamente con código SLATEC.


@node Funciones y variables para polinomios ortogonales,  , Introducción a polinomios ortogonales, orthopoly
@section Funciones y variables para polinomios ortogonales

@deffn {Función} assoc_legendre_p (@var{n}, @var{m}, @var{x})
Función asociada de Legendre de primera especie de grado @var{n} y orden @var{m}.

Referencia: Abramowitz y Stegun, ecuaciones 22.5.37, página 779, 8.6.6
(segunda ecuación), página 334 y  8.2.5, página 333.
@end deffn

@deffn {Función} assoc_legendre_q (@var{n}, @var{m}, @var{x})
Función asociada de Legendre de segunda especie de grado @var{n} y orden @var{m}.

Referencia: Abramowitz y Stegun, ecuaciones 8.5.3 y 8.1.8.
@end deffn

@deffn {Función} chebyshev_t (@var{n}, @var{x})
Función de Chebyshev de primera especie.

Referencia: Abramowitz y Stegun, ecuación 22.5.47, página 779.
@end deffn

@deffn {Función} chebyshev_u (@var{n}, @var{x})
Función de Chebyshev de segunda especie.

Referencia: Abramowitz y Stegun, ecuación 22.5.48, página 779.
@end deffn

@deffn {Función} gen_laguerre (@var{n}, @var{a}, @var{x})
Polinomio de Laguerre generalizado de grado @var{n}.

Referencia: Abramowitz y Stegun, ecuación 22.5.54, página 780.
@end deffn

@deffn {Función} hermite (@var{n}, @var{x})
Polinomio de Hermite.

Referencia: Abramowitz y Stegun, ecuación 22.5.55, página 780.
@end deffn

@deffn {Función} intervalp (@var{e})
Devuelve @code{true} si la entrada es un intervalo y @code{false} en caso contrario.
@end deffn

@deffn {Función} jacobi_p (@var{n}, @var{a}, @var{b}, @var{x})
Polinomio de Jacobi.

Los polinomios de Jacobi están definidos para todo @var{a} y @var{b};
sin embargo, el peso @code{(1 - @var{x})^@var{a} (1 + @var{x})^@var{b}}
no es integrable para @code{@var{a} <= -1} o @code{@var{b} <= -1}.

Referencia: Abramowitz y Stegun, ecuación 22.5.42, página 779.
@end deffn

@deffn {Función} laguerre (@var{n}, @var{x})
Polinomio de Laguerre.

Referencia: Abramowitz y Stegun, ecuaciones 22.5.16 y 22.5.54, página 780.
@end deffn

@deffn {Función} legendre_p (@var{n}, @var{x})
Polinomio de Legendre de primera especie.

Referencia: Abramowitz y Stegun, ecuaciones 22.5.50 y 22.5.51, página 779.
@end deffn

@deffn {Función} legendre_q (@var{n}, @var{x})
Polinomio de Legendre de segunda especie.

Referencia: Abramowitz y Stegun, ecuaciones 8.5.3 y 8.1.8.
@end deffn

@deffn {Función} orthopoly_recur (@var{f}, @var{args})
Devuelve una relación recursiva para la familia de funciones
ortogonales @var{f} con argumentos @var{args}. La recursión se hace con respecto
al grado del polinomio.

@c ===beg===
@c orthopoly_recur (legendre_p, [n, x]);
@c ===end===
@example
(%i1) orthopoly_recur (legendre_p, [n, x]);
                    (2 n + 1) P (x) x - n P     (x)
                               n           n - 1
(%o1)   P     (x) = -------------------------------
         n + 1                   n + 1
@end example

El segundo argumento de @code{orthopoly_recur} debe ser una lista con
el número correcto de argumentos para la función @var{f}; si no
lo es, Maxima emite un mensaje de error.

@c ===beg===
@c orthopoly_recur (jacobi_p, [n, x]);
@c ===end===
@example
(%i1) orthopoly_recur (jacobi_p, [n, x]);

Function jacobi_p needs 4 arguments, instead it received 2
 -- an error.  Quitting.  To debug this try debugmode(true);
@end example

Además, si @var{f} no es el nombre de ninguna de las 
familias de polinomios ortogonales, se emite otro mensaje
de error.

@c ===beg===
@c orthopoly_recur (foo, [n, x]);
@c ===end===
@example
(%i1) orthopoly_recur (foo, [n, x]);

A recursion relation for foo isn't known to Maxima
 -- an error.  Quitting.  To debug this try debugmode(true);
@end example
@end deffn

@defvr {Variable opcional} orthopoly_returns_intervals
Valor por defecto: @code{true}

Si @code{orthopoly_returns_intervals} vale @code{true}, los números
decimales en coma flotante se retornan con el formato 
@code{interval (@var{c}, @var{r})}, donde @var{c} es el centro del
intervalo y @var{r} su radio. El centro puede ser un número complejo,
en cuyo caso el intervalo es un disco en el plano complejo.
@end defvr

@deffn {Función} orthopoly_weight (@var{f}, @var{args})

Devuelve una lista con tres elementos; el primer elemento es la
fórmula del peso para la familia de polinomios ortogonales @var{f}
con los argumentos dados por la lista @var{args}; el segundo y tercer
elementos son los extremos inferior y superior del intervalo de
ortogonalidad. Por ejemplo,

@c ===beg===
@c w : orthopoly_weight (hermite, [n, x]);
@c integrate (w[1] * hermite (3, x) * hermite (2, x), x, w[2], w[3]);
@c ===end===
@example
(%i1) w : orthopoly_weight (hermite, [n, x]);
                            2
                         - x
(%o1)                 [%e    , - inf, inf]
(%i2) integrate (w[1] * hermite (3, x) * hermite (2, x), x, w[2], w[3]);
(%o2)                           0
@end example

La variable principal de @var{f} debe ser un símbolo, en caso
contrario Maxima emite un mensaje de error.
@end deffn

@deffn {Función} pochhammer (@var{n}, @var{x})
Símbolo de Pochhammer. Para enteros no negativos @var{n} con
@code{@var{n} <= pochhammer_max_index}, la expresión 
@code{pochhammer (@var{x}, @var{n})} se evalúa como el producto 
@code{@var{x} (@var{x} + 1) (@var{x} + 2) ... (@var{x} + n - 1)} si 
@code{@var{n} > 0} y como 1 si @code{@var{n} = 0}. Para @var{n} negativo,
@code{pochhammer (@var{x}, @var{n})} se define como 
@code{(-1)^@var{n} / pochhammer (1 - @var{x}, -@var{n})}.
Así por ejemplo,

@c ===beg===
@c pochhammer (x, 3);
@c pochhammer (x, -3);
@c ===end===
@example
(%i1) pochhammer (x, 3);
(%o1)                   x (x + 1) (x + 2)
(%i2) pochhammer (x, -3);
                                 1
(%o2)               - -----------------------
                      (1 - x) (2 - x) (3 - x)
@end example

A fin de convertir el símbolo de Pochhammer en un cociente 
de funciones gamma (véase Abramowitz y Stegun, ecuación 6.1.22),
hágase uso de @code{makegamma}. Por ejemplo,

@c ===beg===
@c makegamma (pochhammer (x, n));
@c ===end===
@example
(%i1) makegamma (pochhammer (x, n));
                          gamma(x + n)
(%o1)                     ------------
                            gamma(x)
@end example

Si @var{n} es mayor que @code{pochhammer_max_index} o si @var{n}
es simbólico, @code{pochhammer} devuelve una forma nominal.

@c ===beg===
@c pochhammer (x, n);
@c ===end===
@example
(%i1) pochhammer (x, n);
(%o1)                         (x)
                                 n
@end example
@end deffn

@defvr {Variable opcional} pochhammer_max_index
Valor por defecto: 100

@code{pochhammer (@var{n}, @var{x})} se evalúa como un producto
si y sólo si @code{@var{n} <= pochhammer_max_index}.

Ejemplos:

@c ===beg===
@c pochhammer (x, 3), pochhammer_max_index : 3;
@c pochhammer (x, 4), pochhammer_max_index : 3;
@c ===end===
@example
(%i1) pochhammer (x, 3), pochhammer_max_index : 3;
(%o1)                   x (x + 1) (x + 2)
(%i2) pochhammer (x, 4), pochhammer_max_index : 3;
(%o2)                         (x)
                                 4
@end example

Referencia: Abramowitz y Stegun, ecuación 6.1.16, página 256.
@end defvr

@deffn {Función} spherical_bessel_j (@var{n}, @var{x})
Función de Bessel esférica de primera especie.

Referencia: Abramowitz y Stegun, ecuaciones 10.1.8, página 437 y 10.1.15, página 439.
@end deffn

@deffn {Función} spherical_bessel_y (@var{n}, @var{x})
Función de Bessel esférica de segunda especie.

Referencia: Abramowitz y Stegun, ecuaciones 10.1.9, página 437 y 10.1.15, página 439.
@end deffn

@deffn {Función} spherical_hankel1 (@var{n}, @var{x})
Función esférica de Hankel de primera especie.

Referencia: Abramowitz y Stegun, ecuación 10.1.36, página 439.
@end deffn

@deffn {Función} spherical_hankel2 (@var{n}, @var{x})
Función esférica de Hankel de segunda especie.

Referencia: Abramowitz y Stegun, ecuación 10.1.17, página 439.
@end deffn

@deffn {Función} spherical_harmonic (@var{n}, @var{m}, @var{x}, @var{y})
Función armónica esférica.

Referencia: Merzbacher 9.64.
@end deffn

@deffn {Función} unit_step (@var{x})
Función de escalón unidad continua por la izquierda, definida de
tal forma que @code{unit_step (@var{x})} se anula para @code{@var{x} <= 0}
y es igual a 1 para @code{@var{x} > 0}.

En caso de ser necesaria una función escalón unidad que tome el
valor 1/2 en el origen, utilícese @code{(1 + signum (@var{x}))/2}.
@end deffn

@deffn {Función} ultraspherical (@var{n}, @var{a}, @var{x})
Polinomio ultraesférico o de Gegenbauer.

Referencia: Abramowitz y Stegun, ecuación 22.5.46, página 779.
@end deffn

