@c English version 2011-08-21
@menu
* Introducción a la transformada rápida de Fourier::
* Funciones y variables para la transformada rápida de Fourier::
* Funciones para la resolución numérica de ecuaciones::
* Introducción a la resolución numérica de ecuaciones diferenciales::
* Funciones para la resolución numérica de ecuaciones diferenciales::
@end menu

@node Introducción a la transformada rápida de Fourier, Funciones y variables para la transformada rápida de Fourier, Métodos numéricos, Métodos numéricos
@section Introducción a la transformada rápida de Fourier

El paquete @code{fft} contiene funciones para el cálculo numérico (no simbólico)
de la transformada rápida de Fourier.






@node Funciones y variables para la transformada rápida de Fourier, Funciones para la resolución numérica de ecuaciones, Introducción a la transformada rápida de Fourier, Métodos numéricos
@section Funciones y variables para la transformada rápida de Fourier

@deffn {Función} polartorect (@var{magnitude_array}, @var{phase_array})

Transforma valores complejos de la forma @code{r %e^(%i t)} a la forma
@code{a + b %i}, siendo @var{r} el módulo y @var{t} la fase.
Ambos valores @var{r} y @var{t} son arrays unidimensionales cuyos
tamños son iguales a la misma potencia de dos.

Los valores originales de los arrays de entrada son reemplazados por
las partes real e imaginaria, @code{a} y @code{b}, de los correspondientes
números complejos. El resultado se calcula como

@example
a = r cos(t)
b = r sin(t)
@end example

@code{polartorect} es la función inversa de @code{recttopolar}.

Para utilizar esta función ejecútese antes @code{load("fft")}.
Véase también @code{fft}.

@end deffn



@deffn {Función} recttopolar (@var{real_array}, @var{imaginary_array})

Transforma valores complejos de la forma @code{a + b %i} a la forma
@code{r %e^(%i t)}, siendo @var{a} la parte real y @var{a} la imaginaria.
Ambos valores @var{a} y @var{b} son arrays unidimensionales cuyos
tamños son iguales a la misma potencia de dos.

Los valores originales de los arrays de entrada son reemplazados por
los módulos y las fases, @code{r} y @code{t}, de los correspondientes
números complejos. El resultado se calcula como

@example
r = sqrt(a^2 + b^2)
t = atan2(b, a)
@end example

El ángulo calculado pertence al rango de @code{-%pi} a @code{%pi}. 

@code{recttopolar} es la función inversa de @code{polartorect}.

Para utilizar esta función ejecútese antes @code{load("fft")}.
Véase también @code{fft}.

@end deffn



@deffn {Función} inverse_fft (@var{y})

Calcula la transformada inversa rápida de Fourier.

@var{y} es una lista o array (declarado o no) que contiene los datos a
transformar. El número de elementos debe ser una potencia de dos.
Los elementos deben ser números literales (enteros, racionales,
de punto flotante o decimales grandes), constantes simbólicas,
expresiones del tipo @code{a + b*%i}, siendo @code{a} y @code{b}
números literales, o constantes simbólicas.

La función @code{inverse_fft} devuelve un nuevo objeto del
mismo tipo que @var{y}, el cual no se ve modificado. Los
resultados se calculan siempre como decimales o expresiones @code{a + b*%i},
siendo @code{a} y @code{b} decimales.

La transformada inversa discreta de Fourier se define como se indica
a continuación. Si @code{x} es el resultado de la transformada inversa,
entonces para @code{j} entre 0 y @code{n - 1} se tiene

@example
x[j] = sum(y[k] exp(-2 %i %pi j k / n), k, 0, n - 1)
@end example

Para utilizar esta función ejecútese antes @code{load("fft")}.

Véanse también @code{fft} (transformada directa), @code{recttopolar} y @code{polartorect}.

Ejemplos:

Datos reales.

@c ===beg===
@c load ("fft") $
@c fpprintprec : 4 $
@c L : [1, 2, 3, 4, -1, -2, -3, -4] $
@c L1 : inverse_fft (L);
@c L2 : fft (L1);
@c lmax (abs (L2 - L));
@c ===end===
@example
(%i1) load ("fft") $
(%i2) fpprintprec : 4 $
(%i3) L : [1, 2, 3, 4, -1, -2, -3, -4] $
(%i4) L1 : inverse_fft (L);
(%o4) [0.0, 14.49 %i - .8284, 0.0, 2.485 %i + 4.828, 0.0, 
                       4.828 - 2.485 %i, 0.0, - 14.49 %i - .8284]
(%i5) L2 : fft (L1);
(%o5) [1.0, 2.0 - 2.168L-19 %i, 3.0 - 7.525L-20 %i, 
4.0 - 4.256L-19 %i, - 1.0, 2.168L-19 %i - 2.0, 
7.525L-20 %i - 3.0, 4.256L-19 %i - 4.0]
(%i6) lmax (abs (L2 - L));
(%o6)                       3.545L-16
@end example

Datos complejos.

@c ===beg===
@c load ("fft") $
@c fpprintprec : 4 $
@c L : [1, 1 + %i, 1 - %i, -1, -1, 1 - %i, 1 + %i, 1] $
@c L1 : inverse_fft (L);
@c L2 : fft (L1);
@c lmax (abs (L2 - L));
@c ===end===
@example
(%i1) load ("fft") $
(%i2) fpprintprec : 4 $                 
(%i3) L : [1, 1 + %i, 1 - %i, -1, -1, 1 - %i, 1 + %i, 1] $
(%i4) L1 : inverse_fft (L);
(%o4) [4.0, 2.711L-19 %i + 4.0, 2.0 %i - 2.0, 
- 2.828 %i - 2.828, 0.0, 5.421L-20 %i + 4.0, - 2.0 %i - 2.0, 
2.828 %i + 2.828]
(%i5) L2 : fft (L1);
(%o5) [4.066E-20 %i + 1.0, 1.0 %i + 1.0, 1.0 - 1.0 %i, 
1.55L-19 %i - 1.0, - 4.066E-20 %i - 1.0, 1.0 - 1.0 %i, 
1.0 %i + 1.0, 1.0 - 7.368L-20 %i]
(%i6) lmax (abs (L2 - L));                    
(%o6)                       6.841L-17
@end example

@end deffn

@deffn {Función} fft (@var{x})

Calcula la transformada rápida compleja de Fourier.

@var{x} es una lista o array (declarado o no) que contiene los datos a
transformar. El número de elementos debe ser una potencia de dos.
Los elementos deben ser números literales (enteros, racionales,
de punto flotante o decimales grandes), constantes simbólicas,
expresiones del tipo @code{a + b*%i}, siendo @code{a} y @code{b}
números literales, o constantes simbólicas.

La función @code{fft} devuelve un nuevo objeto del
mismo tipo que @var{x}, el cual no se ve modificado. Los
resultados se calculan siempre como decimales o expresiones @code{a + b*%i},
siendo @code{a} y @code{b} decimales.

La transformada discreta de Fourier se define como se indica
a continuación. Si @code{y} es el resultado de la transformada inversa,
entonces para @code{k} entre 0 y @code{n - 1} se tiene

@example
y[k] = (1/n) sum(x[j] exp(+2 %i %pi j k / n), j, 0, n - 1)
@end example

Si los datos @var{x} son reales, los coeficientes reales @code{a} y @code{b}
se pueden calcular de manera que 

@example
x[j] = sum(a[k]*cos(2*%pi*j*k/n)+b[k]*sin(2*%pi*j*k/n), k, 0, n/2)
@end example

con

@example
a[0] = realpart (y[0])
b[0] = 0
@end example

y, para k entre 1 y n/2 - 1,

@example
a[k] = realpart (y[k] + y[n - k])
b[k] = imagpart (y[n - k] - y[k])
@end example

y

@example
a[n/2] = realpart (y[n/2])
b[n/2] = 0
@end example

Para utilizar esta función ejecútese antes @code{load("fft")}.

Véanse también @code{inverse_fft} (transformada inversa), @code{recttopolar} y @code{polartorect}.

Ejemplos:

Datos reales.

@c ===beg===
@c load ("fft") $
@c fpprintprec : 4 $
@c L : [1, 2, 3, 4, -1, -2, -3, -4] $
@c L1 : fft (L);
@c L2 : inverse_fft (L1);
@c lmax (abs (L2 - L));
@c ===end===
@example
(%i1) load ("fft") $
(%i2) fpprintprec : 4 $
(%i3) L : [1, 2, 3, 4, -1, -2, -3, -4] $
(%i4) L1 : fft (L);
(%o4) [0.0, - 1.811 %i - .1036, 0.0, .6036 - .3107 %i, 0.0, 
                         .3107 %i + .6036, 0.0, 1.811 %i - .1036]
(%i5) L2 : inverse_fft (L1);
(%o5) [1.0, 2.168L-19 %i + 2.0, 7.525L-20 %i + 3.0, 
4.256L-19 %i + 4.0, - 1.0, - 2.168L-19 %i - 2.0, 
- 7.525L-20 %i - 3.0, - 4.256L-19 %i - 4.0]
(%i6) lmax (abs (L2 - L));
(%o6)                       3.545L-16
@end example

Datos complejos.

@c ===beg===
@c load ("fft") $
@c fpprintprec : 4 $
@c L : [1, 1 + %i, 1 - %i, -1, -1, 1 - %i, 1 + %i, 1] $
@c L1 : fft (L);
@c L2 : inverse_fft (L1);
@c lmax (abs (L2 - L));
@c ===end===
@example
(%i1) load ("fft") $
(%i2) fpprintprec : 4 $
(%i3) L : [1, 1 + %i, 1 - %i, -1, -1, 1 - %i, 1 + %i, 1] $
(%i4) L1 : fft (L);
(%o4) [0.5, .3536 %i + .3536, - 0.25 %i - 0.25, 
0.5 - 6.776L-21 %i, 0.0, - .3536 %i - .3536, 0.25 %i - 0.25, 
0.5 - 3.388L-20 %i]
(%i5) L2 : inverse_fft (L1);
(%o5) [1.0 - 4.066E-20 %i, 1.0 %i + 1.0, 1.0 - 1.0 %i, 
- 1.008L-19 %i - 1.0, 4.066E-20 %i - 1.0, 1.0 - 1.0 %i, 
1.0 %i + 1.0, 1.947L-20 %i + 1.0]
(%i6) lmax (abs (L2 - L));
(%o6)                       6.83L-17
@end example

Cálculo de los coeficientes del seno y coseno.

@c ===beg===
@c load ("fft") $
@c fpprintprec : 4 $
@c L : [1, 2, 3, 4, 5, 6, 7, 8] $
@c n : length (L) $
@c x : make_array (any, n) $
@c fillarray (x, L) $
@c y : fft (x) $
@c a : make_array (any, n/2 + 1) $
@c b : make_array (any, n/2 + 1) $
@c a[0] : realpart (y[0]) $
@c b[0] : 0 $
@c for k : 1 thru n/2 - 1 do
@c    (a[k] : realpart (y[k] + y[n - k]),
@c     b[k] : imagpart (y[n - k] - y[k]));
@c a[n/2] : y[n/2] $
@c b[n/2] : 0 $
@c listarray (a);
@c listarray (b);
@c f(j) := sum (a[k] * cos (2*%pi*j*k / n) + b[k] * sin (2*%pi*j*k / n), k, 0, n/2) $
@c makelist (float (f (j)), j, 0, n - 1);
@c ===end===
@example
(%i1) load ("fft") $
(%i2) fpprintprec : 4 $
(%i3) L : [1, 2, 3, 4, 5, 6, 7, 8] $
(%i4) n : length (L) $
(%i5) x : make_array (any, n) $
(%i6) fillarray (x, L) $
(%i7) y : fft (x) $
(%i8) a : make_array (any, n/2 + 1) $
(%i9) b : make_array (any, n/2 + 1) $
(%i10) a[0] : realpart (y[0]) $
(%i11) b[0] : 0 $
(%i12) for k : 1 thru n/2 - 1 do
   (a[k] : realpart (y[k] + y[n - k]),
    b[k] : imagpart (y[n - k] - y[k]));
(%o12)                        done
(%i13) a[n/2] : y[n/2] $
(%i14) b[n/2] : 0 $
(%i15) listarray (a);
(%o15)          [4.5, - 1.0, - 1.0, - 1.0, - 0.5]
(%i16) listarray (b);
(%o16)           [0, - 2.414, - 1.0, - .4142, 0]
(%i17) f(j) := sum (a[k] * cos (2*%pi*j*k / n) + b[k] * sin (2*%pi*j*k / n), k, 0, n/2) $
(%i18) makelist (float (f (j)), j, 0, n - 1);
(%o18)      [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
@end example

@end deffn










@node Funciones para la resolución numérica de ecuaciones, Introducción a la resolución numérica de ecuaciones diferenciales, Funciones y variables para la transformada rápida de Fourier, Métodos numéricos
@section Funciones para la resolución numérica de ecuaciones



@deffn {Función} horner (@var{expr}, @var{x})
@deffnx {Función} horner (@var{expr})
Cambia el formato de @var{expr} según la regla de Horner utilizando @var{x} como variable principal, si ésta se especifica. El argumento @code{x} se puede omitir, en cuyo caso se considerará como variable principal la de @var{expr} en su formato racional canónico (CRE).

La función @code{horner} puede mejorar las estabilidad si @code{expr} va a ser numéricamente evaluada. También es útil si Maxima se utiliza para generar programas que serán ejecutados en Fortran. Véase también @code{stringout}.

@example
(%i1) expr: 1e-155*x^2 - 5.5*x + 5.2e155;
                           2
(%o1)            1.0E-155 x  - 5.5 x + 5.2E+155
(%i2) expr2: horner (%, x), keepfloat: true;
(%o2)            (1.0E-155 x - 5.5) x + 5.2E+155
(%i3) ev (expr, x=1e155);
Maxima encountered a Lisp error:

 floating point overflow

Automatically continuing.
To reenable the Lisp debugger set *debugger-hook* to nil.
(%i4) ev (expr2, x=1e155);
(%o4)                       7.0E+154
@end example

@end deffn


@deffn {Función} find_root (@var{expr}, @var{x}, @var{a}, @var{b}, [@var{abserr}, @var{relerr}])
@deffnx {Función} find_root (@var{f}, @var{a}, @var{b}, [@var{abserr}, @var{relerr}])
@deffnx {Función} bf_find_root (@var{expr}, @var{x}, @var{a}, @var{b}, [@var{abserr}, @var{relerr}])
@deffnx {Función} bf_find_root (@var{f}, @var{a}, @var{b}, [@var{abserr}, @var{relerr}])
@deffnx {Variable opcional} find_root_error
@deffnx {Variable opcional} find_root_abs
@deffnx {Variable opcional} find_root_rel

Calcula una raíz de la expresión @var{expr} o de
la función @var{f} en el intervalo cerrado @math{[@var{a}, @var{b}]}.
La expresión @var{expr} puede ser una ecuación, en cuyo caso 
@code{find_root} busca una raíz de
@code{lhs(@var{expr}) - rhs(@var{expr})}.

Dado que Maxima puede evaluar @var{expr} o @var{f} en 
@math{[@var{a}, @var{b}]}, entonces, si @var{expr} o @var{f} es
continua, @code{find_root} encuentrará la raíz
buscada, o raíces, en caso de existir varias.

La función @code{find_root} aplica al principio la
búsqueda por bipartición. Si la expresión es lo suficientemente
suave, entonces @code{find_root} aplicará el método
de interpolación lineal.

@code{bf_find_root} es una versión de @code{find_root} para números
reales de precisión arbitraria (bigfloat). La función se 
evalúa utilizando la aritmética de estos números, devolviendo
un resultado numérico de este tipo. En cualquier otro aspecto,
@code{bf_find_root} es idéntica a @code{find_root}, siendo la
explicación que sigue igualmente válida para @code{bf_find_root}. 

La precisión de @code{find_root} está controlada por @code{abserr} y
@code{relerr}, que son claves opcionales para @code{find_root}. 
Estas claves toman la forma @code{key=val}. Las claves disponibles son:

@table @code
@item abserr
Error absoluto deseado de la función en la raíz. El
valor por defecto es @code{find_root_abs}. 
@item relerr
Error relativo deseado de la raíz. El valor por defecto
es @code{find_root_rel}.
@end table

@code{find_root} se detiene cuando la función alcanza un valor menor o
igual que @code{abserr}, o si las sucesivas aproximaciones @var{x_0}, @var{x_1}
difieren en no más que @code{relerr * max(abs(x_0), abs(x_1))}. Los
valores por defecto de @code{find_root_abs} y @code{find_root_rel} son
ambos cero.

@code{find_root} espera que la función en cuestión tenga signos
diferentes en los extremos del intervalo.
Si la función toma valores numéricos en ambos extremos y estos
números son del mismo signo, entonces
el comportamiento de @code{find_root} se controla con @code{find_root_error}.
Cuando @code{find_root_error} vale @code{true}, @code{find_root}
devuelve un mensaje de error; en caso contrario, @code{find_root}
devuelve el valor de @code{find_root_error}. El valor por defecto
de @code{find_root_error} es @code{true}.

Si en algún momento del proceso de búsqueda @var{f} alcanza un valor
no numérico, @code{find_root} devuelve una expresión parcialmente evaluada.

Se ignora el orden de @var{a} y @var{b}; la región de búsqueda es
@math{[min(@var{a}, @var{b}), max(@var{a}, @var{b})]}.

Ejemplos:
@c PREVIOUS EXAMPLE STUFF -- MAY WANT TO BRING TRANSLATE BACK INTO THE EXAMPLE
@c f(x):=(mode_declare(x,float),sin(x)-x/2.0);
@c interpolate(sin(x)-x/2,x,0.1,%pi)       time= 60 msec
@c interpolate(f(x),x,0.1,%pi);            time= 68 msec
@c translate(f);
@c interpolate(f(x),x,0.1,%pi);            time= 26 msec
@c interpolate(f,0.1,%pi);                 time=  5 msec

@c ===beg===
@c f(x) := sin(x) - x/2;
@c find_root (sin(x) - x/2, x, 0.1, %pi);
@c find_root (sin(x) = x/2, x, 0.1, %pi);
@c find_root (f(x), x, 0.1, %pi);
@c find_root (f, 0.1, %pi);
@c find_root (exp(x) = y, x, 0, 100);
@c find_root (exp(x) = y, x, 0, 100), y = 10;
@c log (10.0);
@c fpprec:32;
@c 32;
@c bf_find_root (exp(x) = y, x, 0, 100), y = 10;
@c log(10b0);
@c ===end===
@example
(%i1) f(x) := sin(x) - x/2;
                                        x
(%o1)                  f(x) := sin(x) - -
                                        2
(%i2) find_root (sin(x) - x/2, x, 0.1, %pi);
(%o2)                   1.895494267033981
(%i3) find_root (sin(x) = x/2, x, 0.1, %pi);
(%o3)                   1.895494267033981
(%i4) find_root (f(x), x, 0.1, %pi);
(%o4)                   1.895494267033981
(%i5) find_root (f, 0.1, %pi);
(%o5)                   1.895494267033981
(%i6) find_root (exp(x) = y, x, 0, 100);
                            x
(%o6)           find_root(%e  = y, x, 0.0, 100.0)
(%i7) find_root (exp(x) = y, x, 0, 100), y = 10;
(%o7)                   2.302585092994046
(%i8) log (10.0);
(%o8)                   2.302585092994046
(%i9) fpprec:32;
(%o9)                           32
(%i10) bf_find_root (exp(x) = y, x, 0, 100), y = 10;
(%o10)                  2.3025850929940456840179914546844b0
(%i11) log(10b0);
(%o11)                  2.3025850929940456840179914546844b0
@end example

@end deffn



@deffn {Función} newton (@var{expr}, @var{x}, @var{x_0}, @var{eps})
Devuelve una solución aproximada de @code{@var{expr} = 0} obtenida
por el método de Newton, considerando @var{expr} como una función
de una variable, @var{x}.
La búsqueda comienza con @code{@var{x} = @var{x_0}} y continúa
hasta que se verifique @code{abs(@var{expr}) < @var{eps}}, donde
@var{expr} se evalúa con el valor actual de @var{x}.

La función @code{newton} permite que en @var{expr} haya variables
no definidas, siempre y cuando la condición de terminación
@code{abs(@var{expr}) < @var{eps}} pueda reducirse a un valor
lógico @code{true} o @code{false}; de este modo, no es necesario
que @var{expr} tome un valor numérico.

Ejecútese @code{load("newton1")} para cargar esta función.

Véanse también @code{realroots}, @code{allroots}, @code{find_root} y @code{mnewton}.

Ejemplos:

@c ===beg===
@c load ("newton1");
@c newton (cos (u), u, 1, 1/100);
@c ev (cos (u), u = %);
@c assume (a > 0);
@c newton (x^2 - a^2, x, a/2, a^2/100);
@c ev (x^2 - a^2, x = %);
@c ===end===
@example
(%i1) load ("newton1");
(%o1) /usr/share/maxima/5.10.0cvs/share/numeric/newton1.mac
(%i2) newton (cos (u), u, 1, 1/100);
(%o2)                   1.570675277161251
(%i3) ev (cos (u), u = %);
(%o3)                 1.2104963335033528E-4
(%i4) assume (a > 0);
(%o4)                        [a > 0]
(%i5) newton (x^2 - a^2, x, a/2, a^2/100);
(%o5)                  1.00030487804878 a
(%i6) ev (x^2 - a^2, x = %);
                                           2
(%o6)                6.098490481853958E-4 a
@end example

@end deffn







@node Introducción a la resolución numérica de ecuaciones diferenciales, Funciones para la resolución numérica de ecuaciones diferenciales, Funciones para la resolución numérica de ecuaciones, Métodos numéricos
@section Introducción a la resolución numérica de ecuaciones diferenciales

Las ecuaciones diferenciales ordinarias (EDO) que se resuelven con las funciones de esta
sección deben tener la forma
@ifnottex
@example
       dy
       -- = F(x,y)
       dx
@end example
@end ifnottex
@tex
$${{dy}\over{dx}} = F(x,y)$$
@end tex
la cual es una EDO de primer orden. Las ecuaciones diferenciales de orden 
@var{n} deben escribirse como un sistema de @var{n} ecuaciones de primer
orden del tipo anterior. Por ejemplo, una EDO de segundo orden debe escribirse
como un sistema de dos ecuaciones,
@ifnottex
@example
       dx               dy
       -- = G(x,y,t)    -- = F(x,y,t) 
       dt               dt
@end example
@end ifnottex
@tex
$${{dx}\over{dt}} = G(x,y,t) \qquad {{dy}\over{dt}} = F(x,y,t)$$
@end tex

El primer argumento de las funciones debe ser una lista con las expresiones
de los miembros derechos de las EDOs. Las variables cuyas derivadas se representan
por las expresiones anteriores deben darse en una segunda lista. En el caso antes
citado, las variables son @var{x} y @var{y}. La variable independiente, @var{t}
en los mismos ejemplos anteriores, pueden darse mediante una opción adicional. 
Si las expresiones dadas no dependen de esa variable independiente, el sistema
recibe el nombre de autónomo.







@node Funciones para la resolución numérica de ecuaciones diferenciales, , Introducción a la resolución numérica de ecuaciones diferenciales, Métodos numéricos
@section Funciones para la resolución numérica de ecuaciones diferenciales



@deffn {Función} plotdf (@var{dydx}, ...options...)
@deffnx {Función} plotdf (@var{dvdu}, @code{[}@var{u},@var{v}@code{]}, ...options...)
@deffnx {Función} plotdf (@code{[}@var{dxdt},@var{dydt}@code{]}, ...options...)
@deffnx {Función} plotdf (@code{[}@var{dudt},@var{dvdt}@code{]}, @code{[}@var{u},@var{v}@code{]}, ...options...)
Dibuja un campo de direcciones en dos dimensiones @var{x} y @var{y}.

@var{dydx}, @var{dxdt} y @var{dydt} son expresiones que dependen de @var{x} y
@var{y}. Además de esas dos variables, las dos expresiones pueden depender de
un conjunto de parámetros, con valores numéricos que son dados por medio
de la opción @code{parameters} (la sintaxis de esa opción se explica mas al
frente), o con un rango de posibles valores definidos con la opción
@var{sliders}.

Varias otras opciones se pueden incluir dentro del comando, o
seleccionadas en el menú.  Haciendo click en un punto del gráfico se
puede hacer que sea dibujada la curva integral que pasa por ese punto;
lo mismo puede ser hecho dando las coordenadas del punto con la opción
@code{trajectory_at} dentro del comando plotdf. La dirección de
integración se puede controlar con la opción @code{direction}, que
acepta valores de @emph{forward}, @emph{backward} ou @emph{both}. El
número de pasos realizado en la integración numérica se controla
con la opción @code{nsteps} y el incremento del tiempo en cada paso
con la opción @code{tstep}. Se usa el método de Adams Moulton para
hacer la integración numérica; también es posible cambiar para el
método de Runge-Kutta de cuarto orden con ajuste de pasos.

@b{Menú de la ventana del gráfico:}

El menú de la ventana gráfica dispone de las siguientes opciones:
@emph{Zoom}, que permite cambiar el comportamiento del ratón, de
manera que hará posible el hacer zoom en la región del gráfico
haciendo clic con el botón izquierdo. Cada clic agranda la imagen
manteniendo como centro de la misma el punto sobre el cual se ha hecho
clic. Manteniendo pulsada la tecla @key{Shift} mientras se hace clic,
retrocede al tamaño anterior. Para reanudar el cálculo de las
trayectorias cuando se hace clic, seleccine la opción @emph{Integrate}
del menú.

La opción @emph{Config} del menú se puede utilizar para cambiar
la(s) EDO(S) y algunos otros ajustes. Después de hacer los cambios, se
debe utilizar la opción @emph{Replot} para activar los nuevos ajustes.
Si en el campo @emph{Trajectory at} del menú de diálogo de
@emph{Config} se introducen un par de coordenadas y luego se pulsa la
tecla @key{retorno}, se mostrará una nueva curva integral, además de
las ya dibujadas.  Si se selecciona la opción @emph{Replot}, sólo se
mostrará la última curva integral seleccionada.

Manteniendo pulsado el botón derecho del ratón mientras se mueve el
cursor, se puede arrastrar el gráfico horizontal y verticalmente.
Otros parámetros, como pueden ser el número de pasos, el valor
inicial de @var{t}, las coordenadas del centro y el radio, pueden
cambiarse en el submenú de la opción @emph{Config}.

Con la opción @emph{Save}, se puede obtener una copia del gráfico en
una impresora Postscript o guardarlo en un fichero Postscript. Para
optar entre la impresión o guardar en fichero, se debe seleccionar
@emph{Print Options} en la ventana de diálogo de @emph{Config}. Una
vez cubiertos los campos de la ventana de diálogo de @emph{Save},
será necesario seleccionar la opción @emph{Save} del primer menú
para crear el fichero o imprimir el gráfico.

@b{Opciones gráficas:}

La función @code{plotdf} admite varias opciones, cada una de las cuales
es una lista de dos o más elementos. El primer elemento es el nombre de
la opción, y el resto está formado por el valor o valores asignados
a dicha opción.

La función @code{plotdf} reconoce las siguientes opciones:

@itemize @bullet
@item
@dfn{tstep} establece la amplitud de los incrementos en la
variable independiente @var{t}, utilizados para calcular la curva
integral. Si se aporta sólo una expresión @var{dydx}, la variable
@var{x} será directamente proporcional a @var{t}.
El valor por defecto es 0.1.

@item
@dfn{nsteps} establece el número de pasos de longitud
@code{tstep} que se utilizarán en la variable independiente para
calcular la curva integral.
El valor por defecto es 100.

@item
@dfn{direction} establece la dirección de la variable
independiente que será seguida para calcular una curva integral.
Valores posibles son: @code{forward}, para hacer que la variable
independiente aumente @code{nsteps} veces, con incrementos @code{tstep};
@code{backward}, para hacer que la variable independiente
disminuya; @code{both}, para extender la curva integral @code{nsteps}
pasos hacia adelante y @code{nsteps} pasos hacia atrás.
Las palabras @code{right} y @code{left} se pueden utilizar como
sinónimos de @code{forward} y @code{backward}.
El valor por defecto es @code{both}.

@item
@dfn{tinitial} establece el valor inicial de la variable
@var{t} utilizado para calcular curvas integrales. Puesto que las
ecuaciones diferenciales son autónomas, esta opción sólo
aparecerá en los gráficos de las curvas como funciones de @var{t}.
El valor por defecto es 0.

@item
@dfn{versus_t} se utiliza para crear una segunda ventana
gráfica, con el gráfico de una curva integral, como dos funciones
@var{x}, @var{y}, de variable independiente @var{t}. Si se le da a
@code{versus_t} cualquier valor diferente de 0, se mostrará la
segunda ventana gráfica, la cual incluye otro menú, similar
al de la ventana principal.
El valor por defecto es 0.

@item
@dfn{trajectory_at} establece las coordenadas @var{xinitial}
y @var{yinitial} para el extremo inicial de la curva integral.
No tiene asignado valor por defecto.

@item
@dfn{parameters} establece una lista de parámetros,
junto con sus valores numéricos, que son utilizados en la
definición de la ecuación diferencial. Los nombres de los
parámetros y sus valores deben escribirse en formato de cadena
de caracteres como una secuencia de pares @code{nombre=valor}
separados por comas.

@item
@dfn{sliders} establece una lista de parámetros que
se cambiarán interactivamente utilizando barras de deslizamiento,
así como los rangos de variación de dichos parámetros.
Los nombres de los parámetros y sus rangos deben escribirse en formato
de cadena de caracteres como una secuencia de pares @code{nombre=min:max}
separados por comas.

@item
@dfn{xfun} establece una cadena de caracteres con funciones
de @var{x} separadas por puntos y comas para ser representadas por
encima del campo de direcciones. Estas funciones serán interpretadas
por Tcl, no por Maxima.

@item
@dfn{xradius} es la mitad de la longitud del rango de valores
a representar en la dirección x.
El valor por defecto es 10.

@item
@dfn{yradius} es la mitad de la longitud del rango de valores
a representar en la dirección y.
El valor por defecto es 10.

@item
@dfn{xcenter} es la coordenada x del punto situado en el centro
del gráfico.
El valor por defecto es 0.

@item
@dfn{ycenter} es la coordenada y del punto situado en el centro
del gráfico.
El valor por defecto es 0.

@item
@dfn{width} establece el ancho de la ventana gráfica en
píxeles.
El valor por defecto es 500.

@item
@dfn{height} establece la altura de la ventana gráfica en
píxeles.
El valor por defecto es 500.

@end itemize

@b{Ejemplos:}

NOTA: Dependiendo de la interface que se use para Maxima, las funciones
que usan @code{openmath}, incluida @code{plotdf}, pueden desencadenar un
fallo si terminan en punto y coma, en vez del símbolo de
dólar. Para evitar problemas, se usará el símbolo de
dólar en todos ejemplos.

@itemize @bullet
@item
Para mostrar el campo de direcciones de la ecuación diferencial
@math{y' = exp(-x) + y} y la solución que pasa por @math{(2, -0.1)}:
@example
(%i1) load("plotdf")$

(%i2) plotdf(exp(-x)+y,[trajectory_at,2,-0.1]);
@end example

@altfigure{plotdf1, Campo de direcciones de la ecuación diferencial
@math{y' = exp(-x) + y}}

@item
Para mostrar el campo de direcciones de la ecuación diferencial
@math{diff(y,x) = x - y^2} y la solución de condición
inicial @math{y(-1) = 3}, se puede utilizar la sentencia:
@example
(%i3) plotdf(x-y^2,[xfun,"sqrt(x);-sqrt(x)"],
          [trajectory_at,-1,3], [direction,forward],
          [yradius,5],[xcenter,6]);
@end example
El gráfico también muestra la función @math{y = sqrt(x)}.

@altfigure{plotdf2, Campo de direcciones de la ecuación diferencial
@math{diff(y,x) = x - y^2}}

@item
El siguiente ejemplo muestra el campo de direcciones de un oscilador
armónico, definido por las ecuaciones @math{dx/dt = y} y
@math{dy/dt = -k*x/m}, y la curva integral que pasa por
@math{(x,y) = (6,0)}, con una barra de deslizamiento que 
permitirá cambiar el valor de @math{m} interactivamente
(@math{k} permanece fijo a 2):
@example
(%i4) plotdf([y,-k*x/m],[parameters,"m=2,k=2"],
            [sliders,"m=1:5"], [trajectory_at,6,0]);
@end example

@altfigure{plotdf3, Campo de direcciones de un oscilador armónico}

@item
Para representar el campo de direcciones de la ecuación de
Duffing, @math{m*x''+c*x'+k*x+b*x^3 = 0}, se introduce la
variable @math{y=x'} y se hace:
@example
(%i5) plotdf([y,-(k*x + c*y + b*x^3)/m],
              [parameters,"k=-1,m=1.0,c=0,b=1"],
              [sliders,"k=-2:2,m=-1:1"],[tstep,0.1]);
@end example

@altfigure{plotdf4, Campo de direcciones de la ecuación de Duffing}

@item
El campo de direcciones de un péndulo amortiguado,
incluyendo la solución para condiciones iniciales dadas,
con una barra de deslizamiento que se puede utilizar para
cambiar el valor de la masa, @math{m}, y con el gráfico
de las dos variables de estado como funciones del tiempo:

@example
(%i6) plotdf([y,-g*sin(x)/l - b*y/m/l],
         [parameters,"g=9.8,l=0.5,m=0.3,b=0.05"],
         [trajectory_at,1.05,-9],[tstep,0.01],
         [xradius,6],[yradius,14],
         [xcenter,-4],[direction,forward],[nsteps,300],
         [sliders,"m=0.1:1"], [versus_t,1]);
@end example

@altfigure{plotdf5, Campo de direcciones de un péndulo amortiguado}@altfigure{plotdf6, Una solución de un péndulo amortiguado}

@end itemize

@end deffn



@deffn {Función} ploteq (@var{exp}, ...options...)

Dibuja curvas equipotenciales para @var{exp}, que debe ser una expresión
dependiente de dos variables. Las curvas se obtienen integrando la ecuación
diferencial que define las trayectorias ortogonales a las soluciones del 
sistema autónomo que se obtiene del gradiente de la expresión dada.
El dibujo también puede mostrar las curvas integrales de ese sistema
de gradientes (opción @code{fieldlines}).

Este programa también necesita Xmaxima, incluso si se ejecuta Maxima desde
una consola, pues el dibujo se creará por el código Tk de Xmaxima.
Por defecto, la región dibujada estará vacía hasta que el
usuario haga clic en un punto, dé sus coordenadas a través del menú o
mediante la opción @code{trajectory_at}.

La mayor parte de opciones aceptadas por @code{plotdf} se pueden utilizar
también con @code{ploteq} y el aspecto del interfaz es el mismo que el
descrito para @code{plotdf}.

Ejemplo:

@c ===beg===
@c V: 900/((x+1)^2+y^2)^(1/2)-900/((x-1)^2+y^2)^(1/2)$
@c ploteq(V,[x,-2,2],[y,-2,2],[fieldlines,"blue"])$
@c ===end===
@example
(%i1) V: 900/((x+1)^2+y^2)^(1/2)-900/((x-1)^2+y^2)^(1/2)$
(%i2) ploteq(V,[x,-2,2],[y,-2,2],[fieldlines,"blue"])$
@end example

Haciendo clic sobre un punto se dibujará la curva equipotencial que pasa por
ese punto (en rojo) y la trayectoria ortogonal (en azul).

@end deffn



@deffn {Función} rk (@var{ODE}, @var{var}, @var{initial}, @var{dominio})
@deffnx {Función} rk ([@var{ODE1},...,@var{ODEm}], [@var{v1},...,@var{vm}], [@var{init1},...,@var{initm}], @var{dominio})

La primera forma se usa para resolver numéricamente una ecuación
diferencial ordinaria de primer orden (EDO), y la segunda forma resuelve
numéricamente un sistema de @var{m} de esas ecuaciones, usando el método
de Runge-Kutta de cuarto orden. @var{var} representa la variable dependiente.
EDO debe ser una expresión que dependa únicamente de las variables
independiente y dependente, y define la derivada de la variable dependiente
en función de la variable independiente.

La variable independiente se representa con @var{dominio}, que debe ser
una lista con cuatro elementos, como por ejemplo:
@example
[t, 0, 10, 0.1]
@end example
el primer elemento de la lista identifica la variable independiente, el
segundo y tercer elementos son los valores inicial y final para esa
variable, y el último elemento da el valor de los incrementos que
deberán ser usados dentro de ese intervalo.

Si se van a resolver @var{m} ecuaciones, deberá haber @var{m}
variables dependientes @var{v1}, @var{v2}, ..., @var{vm}. Los valores
iniciales para esas variables serán @var{inic1},
@var{inic2}, ..., @var{inicm}. Continuará existiendo apenas una
variable independiente definida por la lista @var{domain}, como en
el caso anterior. @var{EDO1}, ..., @var{EDOm} son las expresiones que
definen las derivadas de cada una de las variables dependientes en
función de la variable independiente. Las únicas variables que
pueden aparecer en cada una de esas expresiones son la variable
independiente y cualquiera de las variables dependientes. Es importante
que las derivadas @var{EDO1}, ..., @var{EDOm} sean colocadas en la lista
en el mismo orden en que fueron agrupadas las variables dependientes;
por ejemplo, el tercer elemento de la lista será interpretado como la
derivada de la tercera variable dependiente.

El programa intenta integrar las ecuaciones desde el valor inicial de la
variable independiente, hasta el valor final, usando incrementos
fijos. Si en algún paso una de las variables dependientes toma un
valor absoluto muy grande, la integración será suspendida en ese
punto.  El resultado será una lista con un número de elementos igual
al número de iteraciones realizadas. Cada elemento en la lista de
resultados es también una lista con @var{m}+1 elementos: el valor de
la variable independiente, seguido de los valores de las variables
dependientes correspondientes a ese punto.

@end deffn



