Intro Maxima
Intro Maxima
Intro Maxima
https://renato.ryn-fismat.es
1
Versión del 4 de febrero de 2021
A Niurka, Renato A. y Sofía
Índice general
I
II
Figura 1.1: ENIAC (izquierda) y J. Von Neumann posando junto a MANIAC-I (derecha).
los ordenadores electrónicos se remonta a finales del 1945, principios del 1946 y estu-
vo muy relacionado con el esfuerzo de los aliados (en este caso americanos y británicos)
por descifrar los famosos códigos alemanes. De hecho durante bastante tiempo solo al-
gunas instituciones tenían alguna de estas máquinas que usualmente eran financiadas
con el presupuesto militar de los EEUU. No es hasta mediados de 1952 que el físico En-
rico Fermi (1901–1954) propuso resolver numéricamente con ayuda de la computadora
MANIAC-I (Mathematical Analyzer Numerical Integrator And Calculator) del Laboratorio
Nacional de Los Alamos (EEUU) — Laboratorio donde nacieron las bombas atómicas y de
hidrógeno del ejército norteamericano— un sistema de ecuaciones no lineales asociada
con cierto sistema de osciladores no lineales, para lo que se asoció con el especialista en
1
En realidad el primer ordenador digital fue el ENIAC (Electronic Numerical Integrator And Calculator)
pero su programa estaba conectado al procesador y debía ser modificado manualmente, es decir si queríamos
resolver un problema distinto había que cambiar las propias conexiones en el ordenador, i.e., cambios en
el programa implicaban cambios en la estructura de la máquina (hardware). Fue el polifacético John von
Neumann quien propuso que se separaran los programas (software) del hardware, por lo que se le considera
el padre de los ordenadores modernos.
1
2
Figura 1.2: El famoso artículo de Fermi, Pasta y Ulam: Studies of nonlinear problems, toma-
do de las obras completas de Fermi pág. 979.
Hoy día un enorme número de personas utiliza diariamente los ordenadores, especial-
mente para navegar por internet, editar textos, jugar, etc. Un smartphone moderno tiene
una potencia de cálculo muy superior a la del MANIAC-I y nos cabe en un bolsillo2 .
No obstante, sería deseable que, aparte de los muchos usos lúdicos que sin duda tie-
nen los ordenadores, también aprendiésemos a utilizarlos como herramienta para resolver
problemas y proyectos relacionados con las matemáticas y demás ciencias. De esta forma
se puede, entre otras cosas, comprobar las predicciones analíticas (teóricas) de una teoría
(tanto matemática como en el contexto del resto de las ciencias) mediante experimentos
2
ENIAC por ejemplo, ocupaba 167m2 , pesaba 27000 Kg y costó medio millón de dólares (6 millones de
dólares actuales) y sólo realizaba 200 ciclos básicos por segundo. Un ciclo básico consiste en la siguiente
secuencia de acciones: buscar datos, decodificar, ejecutar y guardar. Muchos smartphones actuales tienen
procesadores que realizan más de un millón de ciclos por segundo.
R. Álvarez Nodarse Introducción a M AXIMA CAS 3
http://maxima.sourceforge.net y
http://www.gnu.org/software/octave ,
respectivamente4 .
1. Jerónimo Alaminos Prats, Camilo Aparicio del Prado, José Extremera Lizana, Pilar
Muñoz Rivas y Armando R. Villena Muñoz, Prácticas de ordenador con WX M AXIMA,
(Granada, 2010).
2. José Manuel Mira Ros, Manualico de M AXIMA. Disponible desde su web en la Uni-
versidad de Murcia: http://webs.um.es/mira/maxima.php
3. Rafa Rodríguez Galván, M AXIMA con WX M AXIMA: software libre en el aula de mate-
máticas (Cádiz, 2007)
4. Mario Rodríguez Riotorto, Primeros pasos en M AXIMA (Ferrol, 2015). Disponible des-
de la web del autor. http://www.tecnostats.net
M AXIMA es un programa que funciona como una calculadora científica. Las opera-
ciones aritméticas elementales son las habituales: + suma, − resta, ∗ multiplicación, /
división, ˆ potenciación:1
La notación que usa M AXIMA es (%in) y (%om) para indicar la entrada (inchar o in-
put) n-ésima y la salida (outchar u output) m-ésima. Usando, por ejemplo, las órdenes
inchar: "input"; y outchar: "output"; podemos cambiar las (%in) y (%om) por
(%inputn) y (%outputm), respectivamente.
Que las salidas y entradas estén numeradas no es por casualidad. Podemos recuperar
la n-ésima salida simplemente usando %on donde n es el número de la salida (output)
correspondiente. Así %o4 nos devolvería la salida número 4, i.e. 1/2.
Dado que M AXIMA es un programa de cálculo simbólico, trabaja con variables definidas
por símbolos (usualmente letras o letras y números):
(%i6) e;
(%o6) e
Las funciones (comandos) tienen el argumento (o los argumentos) que van entre parénte-
sis, como por ejemplo el comando float(x) que nos da como resultado el valor numérico
de la variable x. En este ejemplo e representa una variable que no tiene ningún argumento
asignado:
1
Normalmente para que M AXIMA calcule es necesario apretar al mismo tiempo las teclas “Schift” (mayús-
culas) y “Enter”.
5
6
(%i7) float(e);
(%o7) e
(%i8) pi;
(%o8) pi
(%i9) float(pi);
(%o9) pi
por lo que su respuesta es la propia variable. Nótese que si escribimos “pi”, (o π, lo que
se puede conseguir con la combinación “Esc” p “Esc”) el resultado es pi. Para los valores
numéricos de las constantes e (base de los logaritmos neperianos) o π M AXIMA usa una
notación distinta:
(%i10) %e;
(%o10) %e
(%i11) float(%e);
(%o11) 2.718281828459045
Si no se le dice lo contrario, M AXIMA trabaja en doble precisión, i.e., con 16 dígitos. Dado
que es un programa simbólico, podemos fijar con cuantas cifras queremos trabajar2 . Para
ello hay que definir la variable fpprec. Para asignar valores a las variables dadas se usan
los “dos puntos”. Por ejemplo si escribimos e: %e habremos definido la variable e con el
valor de la base de los logaritmos neperianos. Vamos a definir el grado de precisión en 50
cifras significativas:
(%i12) fpprec:50;
(%o12) 50
y lo comprobamos pidiendo a M AXIMA que nos de los valores de e y π con 50 cifras, para
lo cual hay que usar el comando bfloat
(%i15) float(%e^7);
(%o15) 1096.633158428459
(%i16) bfloat(%e^7);
(%o16) 1.0966331584284585992637202382881214324422191348336b3
(%i17) %e^7;
(%o17) %e^7
Así si escribimos %e^7 la salida es simplemente e7 pues M AXIMA, como hemos dicho,
trabaja simbólicamente. Si usamos float, la salida es en precisión normal, y sólo si usamos
bfloat nos devuelve el resultado en la precisión definida previamente de 50 cifras. Probar
como ejercicio que ocurre con e70 .
El orden de realización de las operaciones es el habitual. Así en la expresión
2
Aunque formalmente M AXIMA trabaja con precisión infinita (o sea simbólicamente), si queremos obtener
un valor numérico M AXIMA necesita implementar algún algoritmo computacional por lo que el cálculo efectivo
dependerá de la potencia del ordenador y el número de dígitos que queramos. A efectos prácticos con los 16
dígitos con que se trabaja por defecto es más que suficiente a la hora de trabajar numéricamente.
R. Álvarez Nodarse Introducción a M AXIMA CAS 7
(%i18) (2+3^2)^3*(5+2^2);
(%o18) 11979
primero calcula las potencias dentro de cada paréntesis, luego las sumas, luego las poten-
cias externas y finalmente la multiplicación.
Como hemos mencionado, para definir los valores de las variables se usan los dos
puntos. En la secuencia que aparece a continuación se definen la x y la y para que valgan
123 y 321, respectivamente, dejándose la z libre.
De lo anterior se sigue, que, por ejemplo, al realizar la división x/y, M AXIMA simplifica
al máximo el resultado. Nótese también que el resultado de la multiplicación de x ∗ y es
precisamente el valor de 123 ∗ 321. Como vemos en la salida (%o26) la expresión z=2 no
asigna el valor 2 a la variable z, ya que en realidad para M AXIMA z=2 es una ecuación
(como veremos más adelante).
Es importante destacar, además, que hay que escribir el símbolo de cada multiplicación
pues, si por ejemplo escribimos x y en vez de x*y obtenemos un mensaje de error
(%i33) f(%pi);
(%o33) %pi^2-%pi+1
(%i34) float(%);
(%o34) 7.728011747499565
(%i35) float(f(%pi));
(%o35) 7.728011747499565
Nótese que a no ser que pidamos a M AXIMA que trabaje numéricamente, sigue usando
cálculo simbólico (ver el valor de f (π) de la salida 33).
Otro detalle interesante a tener en cuenta es que M AXIMA contiene una ayuda com-
pleta que puede ser invocada desde la propia línea de comandos. Para ello preguntamos a
M AXIMA con ?? delante del comando desconocido
(%i36) ??limit;
0: Functions and Variables for Limits
1: limit (Functions and Variables for Limits)
2: List delimiters (Functions and Variables for Lists)
3: tlimit (Functions and Variables for Limits)
4: zn_primroot_limit (Functions and Variables for Number Theory)
etc.
(%o36) true
Si no existe ningún comando con ese nombre la respuesta es false (en caso contrario, al
final de las explicaciones, la salida es true).
(%i37) ??renato;
(%o37) false
R. Álvarez Nodarse Introducción a M AXIMA CAS 9
Otra de las interesantes opciones de M AXIMA es su potencia gráfica. Para hacer las
gráficas M AXIMA usa G NUPLOT, un potente paquete gráfico GNU. El comando más sencillo
de usar es plot2d (o si usas como interfaz gráfica el WX M AXIMA, wxplot2d que incrusta el
gráfico en la propia sesión de WX M AXIMA). Su sintaxis es muy simple
wxplot2d([funcion1,funcion2,...],[variable,inicio,final],opciones)
Ahora bien, para usar ese comando tenemos que ser muy cuidadosos. Si hacemos en
nuestro caso
obtenemos un error, que simplemente, leyendo nos indica que la variable x ya esta asigna-
da. Eso se resuelve cambiando la variable por otra no usada o, usando una variable muda,
es decir una variable que solo se use dentro del propio comando wxplot2d. Estas variables
se definen colocando delante de la misma el signo ', por ejemplo, en vez de x usamos 'x
35
30
25
20
x2-x+1
15
10
0
-4 -2 0 2 4
x
Figura 2.1: Gráfica de la función de la salida ( %o32) f (x) = x2 − x + 1 (izquierda) tal co-
mo se ve al usar la orden wxplot2d([f('x)], ['x,-5,5]) y pantalla emergente que
vemos si escribimos plot2d([f('x)], ['x,-5,5]). Para esta última, debajo a
la izquierda, se muestran las coordenadas del cursor.
pantalla aparte (de G NUPLOT) y que permite algunas interacciones muy útiles. Por ejemplo
marcando con el ratón en un punto de la ventana emergente podemos ver sus coordenadas
en el ángulo izquierdo inferior (ver figura 2.1).
Por otro lado, si pinchamos con el botón derecho del ratón y nos movemos a otro
punto de la ventana se abre un rectángulo azul y al pinchar el botón derecho obtenemos
un zoom (ampliación) de dicho rectángulo. Un ejemplo lo vemos en la figura 2.2.
La combinación de estas dos operaciones son muy útiles a la hora de resolver pro-
blemas. Por ejemplo si necesitamos saber aproximadamente donde está el cero de una
función, etc.
10
Figura 2.2: Escogiendo una región de la gráfica de la función para hacer una ampliación
de la misma (izquierda) y resultado de dicha ampliación (derecha).
También podemos representar varias gráficas al mismo tiempo. Para ello creamos una
lista3 de funciones de la siguiente forma [f1(x),...,fn(x)]. En el ejemplo representa-
mos las funciones f (x), sen(2x) y arctan(x) —ver gráfica 2.3 (derecha)—.
35 7
6 f(x)
30 2 sen(x)
5
25 atan(x)
4
20 3
f(x)
15 2
1
10
0
5 -1
0 -2
-4 -2 0 2 4 -2 -1.5 -1 -0.5 0 0.5 1 1.5 2
x x
Si comparamos los gráficos mostrados en la figura 2.3 con los que vemos en nuestra
sesión notaremos algunas diferencias. Por ejemplo las lineas de éstos últimos son más
finas, aparece la leyenda f (x) en vez de x2 − x + 1, el tamaño de las letras, etc. La razón
está en las opciones gráficas que no vamos a discutir aquí y que pospondremos hasta el
capítulo 3. En particular, en el apartado 3.1.3 veremos como exportar gráficas en distintos
formatos que nos permitan la inclusión de los mismos en documentos de texto (en este
caso L AT E X). En cualquier caso para el caso de la gráfica de la derecha en 2.3 podemos
usar la orden
wxplot2d([f('x),2*sin('x),atan('x)], ['x,-2,2],[ylabel,"y"],
Las listas no son más que expresiones de la forma [objeto1,...,objetoN], donde objeto1, ...,
3
objetoN son objetos cuales quiera (números, variables, gráficas, listas, ...). Para más detalle véase la pági-
na 14.
R. Álvarez Nodarse Introducción a M AXIMA CAS 11
[style,[lines,3]],[legend,"f(x)","2 sen(x)","atan(x)"]);
(%i42) log(10);
(%o42) log(10)
(%i43) float(%);
(%o43) 2.302585092994046
(%i44) log(%e);
(%o44) 1
(%i45) fac:15!;
(%o45) 1307674368000
En el próximo apartado se incluye una lista de algunas de las funciones más usadas en
M AXIMA.
Otra de las bondades de M AXIMA es que cuenta con un gran repertorio de comandos
de manipulación algebraica, basta pinchar en la pestaña “Simplificar” y veremos las mu-
chas posibilidades. A modo de ejemplo factorizaremos el factorial anterior (que al ser un
número, M AXIMA lo que hace es encontrar sus factores primos).
(%i46) factor(fac);
(%o46) 2^11*3^6*5^3*7^2*11*13
(%i47) factor(x^2+x+6);
(%o47) 2*3*2543
(%i48) x;
(%o48) 123
Claro, x estaba asignada al valor 123. Una opción es usar variables mudas
o bien, limpiar el valor de una variable, para lo cual usamos el comando kill
(%i50) kill(x); x;
(%o51) done
12
Ahora ya podemos usar sin problemas los comandos de simplificación usando la variable
x, como por ejemplo, ratsimp que
(%i52) ratsimp((x^2-1)/(x-1));
(%o52) x+1
Conviene saber que los comandos functions y values nos dicen en cada momento las
funciones y las variables que están asignadas en la sesión. Si queremos saber cual es el la
función asignada a cierta expresión, por ejemplo a f, escribimos fundef(f).
Si queremos limpiar todas las variables4 de nuestra sesión podemos usar el comando
kill(all)
(%i53) kill(all);
(%o0) done
Nótese que el número del output es 0. Esta orden limpia toda la memoria, incluido los
paquetes cargados previamente, por lo que si queremos volverlos a usar hay que cargarlos
nuevamente.
Las ecuaciones se definen en M AXIMA de forma habitual, mediante el signo igual, i.e.,
miembro izquierdo = miembro derecho, por ejemplo x^2-4=0 define la ecuación x2 −4 = 0.
Lo interesante es que, definida una ecuación, podemos resolverla analíticamente con el
comando solve:
(%i1) solve(x^2-4=0,x);
(%o1) [x=-2,x=2]
Además, M AXIMA lo hace simbólicamente, como ya hemos mencionado más de una vez.
Incluso da las soluciones complejas si es necesario
(%i2) solve(x^2-4=a,x);
(%o2 [x=-sqrt(a+4),x=sqrt(a+4)]
(%i3) solve(x^2=-1);
(%o3) [x=-%i,x=%i]
(%i4) solve(x^5=1,x);
(%o4) [x=%e^((2*%i*%pi)/5),x=%e^((4*%i*%pi)/5),
x=%e^(-(4*%i*%pi)/5),x=%e^(-(2*%i*%pi)/5),x=1]
(%i5) rectform(%);
(%o5) [x=%i*sin((2*%pi)/5)+cos((2*%pi)/5),
x=%i*sin((4*%pi)/5)+cos((4*%pi)/5),
x=cos((4*%pi)/5)-%i*sin((4*%pi)/5),
x=cos((2*%pi)/5)-%i*sin((2*%pi)/5),
x=1]
(%i6) solve(x^7+2*x+1);
(%o6) [0=x^7+2*x+1]
¿Qué ha pasado? Pues que no existe una solución analítica para esta ecuación y M AXIMA,
simplemente, da como salida la misma entrada.
Finalmente, para grabar la sesión, podemos usar la opción “Guardar” en la pestaña
“Archivo” de wxMaxima.
Antes de pasar al siguiente apartado sobre listas, debemos mencionar que para que
M AXIMA reconozca el directorio local de trabajo (lo que es importante a la hora de impor-
tar y exportar ficheros, por ejemplo) es conveniente definir la variable file_search_maxima.
En este ejemplo (con L INUX) el directorio de búsqueda es /home/renato/. La forma más
sencilla de hacerlo es mediante la opción “Añadir a la ruta” (Add to path) en la pestaña
“Maxima” del menú del programa:
2.2. Listas.
Hemos tenido necesidad antes de crear una lista, es decir expresiones de la forma
[objeto1, ..., objetoN], donde objeto1, ..., objetoN son objetos cuales quiera (nú-
meros, variables, gráficas, listas, ...). El uso de listas y el tratamiento de las mismas es de
gran importancia en M AXIMA así que veamos brevemente como tratar estos objetos.
Las listas pueden ser de cualquier tipo de objetos. Por ejemplo
donde "hola soy renato" es una cadena de caracteres. Las cadenas son objetos intere-
santes de mucha utilidad en M AXIMA. Aunque apenas las vamos a usar en estas notas
conviene saber que hay un paquete específico para tratar con ellas: stringproc cuya des-
cripción se puede encontrar en [1].
Si queremos sacar el k-ésimo elemento de la lista l anterior escribimos l[k]
(%i2) l[3];
(%o2) sin(x)
(%i3) l[4];
(%o3) "hola soy renato"
Los primeros diez elementos de una lista también se pueden obtener mediante los
comandos first, second,..., tenth.
Las listas se pueden crear si conocemos una expresión generadora. Para ello usamos el
comando makelist cuya sintaxis es
que lo que hace es generar una lista donde la entrada k-ésima es el resultado de evaluar
la expresión expr para cada k desde k_i inicial hasta k_f final con paso paso.
Por ejemplo, vamos a generar la lista de los números de la forma k 2 + 1 comenzando
por k = 0 hasta k = 5 escribimos
(%i4) makelist(k^2+1,k,0,5);
(%o4) [1,2,5,10,17,26]
El valor por defecto para el paso es 1. Si queremos otro paso distinto debemos especificar-
lo, por ejemplo makelist(k^2,k,0,5,1/2).
También M AXIMA tiene otras formas de escribir las listas. Por ejemplo,
(%i5) makelist(k^2+1,k,i,i+3,1/2);
(%o5) [i^2+1,(i+1/2)^2+1,(i+1)^2+1,(i+3/2)^2+1,(i+2)^2+1]
Otra opción es
cuya salida es una lista de longitud list cuyos elementos son el resultado de evaluar la
expresión expr en k que toma los valores de la lista list
Existe otro comando más flexible para crear listas: create_list que no trataremos aquí y
remitimos al lector al manual [1].
Si queremos agregar una lista lista2 al final de la lista lista1 usamos en comando
append(lista1,lista2). Otra opción es escribir append(lista1,lista2,...,listan)
que genera una nueva lista donde las listas lista1, lista1, etc. van concatenadas.
(%i7) append(l,[z+7,x-2]);
(%o7) [a,2,sin(x),"hola soy renato",z+y,z+7,x-2]
Si queremos mezclar dos listas l y m de forma que el resultado sea un elemento de cada una
de ellas de la forma l[1], m[1], l[2], m[2], ...] usamos el comando join (l, m)
(%i9) last(l);
(%o9) z+y
(%i10) length(l);
(%o10) 5
(%i13) l;
(%o13) [a,2,sin(x),"hola soy renato",z+y]
(%o14) reverse(l);
(%o14) [z+y,"hola soy renato",sin(x),2,a]
Más adelante veremos ejemplos donde nos interesa conocer la posición de cierto ele-
mento en una lista. Para ello M AXIMA cuenta con el comando sublist_indices(lista,P)
que devuelve el índice de los elementos de la lista lista para los cuales el valor del pre-
dicado maybe(P(x)) es true. Antes de ver ejemplos conviene entender lo que hace el
comando maybe.
Cuando escribimos maybe(expr) lo que hace maybe es intentar determinar si el predi-
cado expr se puede deducir de los hechos almacenados en la base de datos gestionada por
la orden assume. Si el predicado se reduce a true o false, maybe devuelve true o false,
respectivamente. En otro caso devuelve unknown. Por ejemplo:
Como se ve al escribir assume (pred_1, ..., pred_n) estamos obligando a M AXIMA que
defina los predicados (o situaciones) definidas por pred_1, ..., pred_n dentro de la
sesión. Hay que tener en cuenta que únicamente son válidos los predicados que cuentan
con los operadores de relación6 <, <=, equal, notequal, >=, >. Para saber en cada
momento que situaciones (o predicados) hemos fijado en la sesión tenemos el comando
facts().
(%i21) facts();
(%o21) [x>1]
Nótese que gracias al comando assume se pueden hacer suposiciones generales sobre las
variables, algo tremendamente útil en muchos casos como veremos luego.
Volvamos con la orden sublist_indices(lista,P) mencionada antes mostrando unos
ejemplos clarificadores.
Aquí, el predicado symbolp nos da la salida true si tenemos un símbolo (no un número)
y false en cualquier otro caso, mientras que numberp es true si tenemos un número.
También podemos usarlo en combinación con la función identity que devuelve su
argumento cualquiera que sea éste.
(%i24) sublist_indices ([1 > 0, 1 < 0, 2 < 1, 2 > 1, 2 > 0], identity);
(%o24) [1,4,5]
(%i25) sublist_indices ([x > 0, x < 0, x < -2], identity);
(%o25) [1]
No podemos usar el símbolo = pues está reservado para las ecuaciones así que para los operadores de
6
Nótese que en la última salida obtenemos el índice 1 porque en nuestra sesión hemos asu-
mido que x > 1. Si eliminamos esa suposición con la orden forget (también kill(all)
limpialas asignaciones de este tipo) la salida es nula pues en ese caso maybe siem-
pre nos da la respuesta unknown7
(%i26) forget(x>1);
(%o26) [x>1]
(%i27) facts();
(%o27) []
(%i28) sublist_indices ([x > 0, x < 0, x < -2], identity);
(%o28) []
Finalmente, veamos unos comandos sencillos que pueden ser de utilidad. Por ejemplo
dada cierta variable podemos preguntarle a M AXIMA si es una lista:
(%i1) kill(all)$
lista:[1,a,sin(x),[1,2],"hola",x+2];
(lista)[1,a,sin(x),[1,2],"hola",x+2]
(%i2) listp(lista);
(%o2) true
(%i3) part(lista,3);
(%o3) sin(x)
cuya salida es efectivamente el tercer elemento de nuestra lista lista. También le pode-
mos preguntar a M AXIMA si cierta expresión es parte de la lista-
(%i4) member(hola,lista);
(%o4) false
(%i5) member("hola",lista);
(%o5) true
Nótese que hola no es lo mismo que "hola", pues en el primer caso es una simple variable
y en el segundo es una cadena. Podemos eliminar un elemento de la lista con la orden
delete(elemento a eliminar,lista). Por ejemplo borramos la cadena "hola",
(%i6) delete("hola",lista);
(%o6) [1,a,sin(x),[1,2],x+2]
(%i7) lista;
(%o7) [1,a,sin(x),[1,2],"hola",x+2]
(%i8) lista:delete("hola",lista);
(lista)[1,a,sin(x),[1,2],x+2]
(%i9) lista;
(%o9) [1,a,sin(x),[1,2],x+2]
7
Probar la secuencia maybe(x>0); maybe(x<0); maybe(x<-2); con, y sin la asunción x > 1.
18
Conviene tener cuidado a la hora de crear una lista. Supongamos que escribimos la se-
cuencia:
(%i11) A[1]:2;A[2]:1;
ARRSTORE: use_fast_arrays=false; allocate a new property hash table for |$a|
(%o10) 2
(%o11) 1
Ya M AXIMA nos indica que algo “raro” está ocurriendo, así que le preguntamos si es una
lista y su respuesta es negativa:
(%i12) listp(A);
(%o12) false
(%i13) listarray(A);
(%o13) [2,1]
De hecho, lo que hemos definido de esta forma es un macro o array, que es otra de las
estructuras de datos que usa M AXIMA y que tiene sus ventajas y desventajas con respecto
a las listas y que no vamos a tratar aquí. Para más información sobre los arrays y las listas
se recomienda al lector consultar el manual de M AXIMA [1].
Vamos ahora a describir las órdenes más importantes que nos permiten trabajar con
los conceptos del cálculo diferencial e integral.
Comenzaremos escribiendo un listado con las funciones más comunes de M AXIMA:
round(x) redondeo de x,
Antes de continuar conviene comentar una opción muy importante relacionada con la
forma como M AXIMA trabaja con los logaritmos y las raíces. Esta opción tiene que ver con
las variables logexpand y radexpand que son las que controlan si se simplifican logaritmos
y radicales de productos, respectivamente. Por defecto su valor es true lo que implica que
expand no desarrolla dichos productos
20
(%i1) log(a*b);
(%o1) log(a*b)
(%i2) sqrt(a*b);
(%o2) sqrt(a*b)
Si queremos que M AXIMA los desarrolle entonces tenemos que asignarle a las variables
logexpand y radexpand el valor all
Otra opción a tener en cuenta es el valor super para logexpand que, además de lo anterior,
desarrolla log(a/b) = log(a) − log(b) cuando a/b es un número racional dado.
(%i9) log(4/5);
(%o9) log(4/5)
(%i10) logexpand:super$
(%i11) log(4/5);
(%o11) log(4)-log(5)
(%i12) log(1/5);
(%o12) -log(5)
(%i13) log(x^r);
(%o13) r*log(x)
(%i14) log(a*b);
(%o14) log(b)+log(a)
(%i15) p:(x^4-2*x^3-7*x^2+20*x-12)/(x^3+11*x^2+4*x-60);
(%o15) (x^4-2*x^3-7*x^2+20*x-12)/(x^3+11*x^2+4*x-60)
(%i16) num(p);
(%o15) x^4-2*x^3-7*x^2+20*x-12
(%i17) denom(p);
(%o17) x^3+11*x^2+4*x-60
(%i18) kill(all);
(%o0) done
Veamos ahora como M AXIMA trabaja con los principales conceptos del cálculo diferen-
cial e integral. Ante todo, M AXIMA sabe calcular límites lı́mx→x0 ± f (x), para ello usa el
comando limit cuya sintaxis es
R. Álvarez Nodarse Introducción a M AXIMA CAS 21
limit(f(x),x,x0,dirección)
(%i1) limit(sin(a*x)/x,x,0);
(%o1) a
(%i2) limit(log(x),x,0);
(%o2) infinity
(%i3) limit(log(x),x,0,plus);
(%o3) -inf
(%i4) limit(log(x),x,0,minus);
(%o4) infinity
Debemos aclarar que infinity es entendido por M AXIMA como el infinito complejo, mien-
tras que inf lo entiende como el +∞ real. Gracias a esto podemos calcular límites infinitos
(%i5) limit((1+2/x)^(x^(1/3)),x,inf);
(%o5) 1
Conviene saber que la salida de limit puede ser und (indefinido) y ind (indefinido pero
acotado). En general, la orden limit lo que hace es aplicar la regla de L’Hospital para el
cálculo de límites. El número de veces que aplica la Regla está controlado por la varia-
ble global lhospitallim cuyo valor por defecto es 4, pasado el cual M AXIMA lo intenta
usando el polinomio de Taylor, para lo cual es necesario que la variable tlimswitch tenga
asignado el valor true. También existe el comando tlimit cuya sintaxis es la misma pero
que usa exclusivamente el desarrollo de Taylor de las funciones involucradas.
n
x2 − 4
log(3x) 2 3
Como ejercicio calcula los límites lı́m , lı́m 1 + y lı́m .
x→0 x n→∞ n x→2 x − 2
ev(expr,var1,var2,...)
(%i6) kill(all)$
(%i1) ev(x^2+3*x+2,x=1);
(%o1) 6
(%i2) ev(x^p+3*x+2,x=2);
(%o2) 2^p+8
(%i3) ev(x^p+3*x+2,x=2,p=2);
(%o3) 12
subst(Sustituto,Original,Expresión)
subst(Ecuación_1,Expresión)
subst([Ecuación_1,Ecuación_2,...Ecuación_n],Expresión)
Por ejemplo,
(%i4) subst(v,x+y,(x+y)^3);
(%o4) v^3
(%i5) subst(x+y=v,(x+y)^3);
(%o5) v^3
subst([x+y=v,x-y=u],(x+y)^3*(x-y)^2)
Pasemos ahora a describir el comando diff que permite calcular derivadas parciales
de cualquier orden de una función. Su sintaxis es
diff(f(x,y),x,k) o diff(f(x,y),x,k,y,m)
(%i6) diff(sin(x^2+2),x);
(%o6) 2*x*cos(x^2+2)
(%i7) diff(x^x, x,3);
(%o7) x^(x-1)*(log(x)+(x-1)/x)+x^x*(log(x)+1)^3+2*x^(x-1)*(log(x)+1)
(%i8) (sin(x))^x;
(%o8) sin(x)^x
(%i9) diff(sin(x)^x, x);
(%o9) sin(x)^x*(log(sin(x))+(x*cos(x))/sin(x))
(%i10) kill(all)$
Además, como vemos, también funciona para funciones definidas por el usuario
Como ya mencionamos al principio M AXIMA recuerda todas las salidas. Como ya vi-
mos, para invocar una salida anterior, digamos la 1, usamos %1. En particular, podemos
recuperar la última usando simplemente la %. Aprovecharemos este ejemplo para hacer
una breve descripción de algunos de los comandos de simplificación con los que cuenta
M AXIMA.
Por ejemplo, la orden ratsimp(%) simplifica la salida anterior (que en nuestro ejemplo
era la derivada de g(x)) —en este caso la misma operación la haría ratsimp( %2)—
(%i3) ratsimp(%);
(%o3) (2*x*cos(x^2/(x^2+1)))/(x^4+2*x^2+1)
R. Álvarez Nodarse Introducción a M AXIMA CAS 23
(%i4) factor(%);
(%o4) (2*x*cos(x^2/(x^2+1)))/(x^2+1)^2
Aquí debemos mencionar que el comando ratsimp está pensado para la simplificación
racional de polinomios (rational simplication), incluso si estos están en el argumento
de una función no polinómica como en el caso del ejemplo anterior. Más adelante en el
apartado 4.1.3 volveremos a hablar de este comando.
Continuaremos nuestra discusión de los conceptos del cálculo con la integración, tanto
definida como indefinida. Para ello M AXIMA cuenta con el comando integrate(f(x),x)
que calcula una primitiva de la función f(x)
(%i5) kill(all)$
(%i1) integrate(sin(2*x), x);
(%o1) -cos(2*x)/2
(%i2) integrate(exp(x^2)*atan(x),x);
(%o2) integrate(%e^x^2*atan(x),x)
(%i3) integrate(x^2/(%e^x^2+1),x);
(%o3) integrate(x^2/(%e^x^2+1),x)
(%i5) integrate(x^2/(%e^x^2+1),x,0,1);
(%o5) integrate(x^2/(%e^x^2+1),x,0,1)
(%i6) integrate(exp(-x^2),x,0,1);
(%o6) (sqrt(%pi)*erf(1))/2
Nótese que en la segunda hay una salida un poco rara. De hecho si le pedimos que evalúe
numéricamente dicha salida obtenemos un valor numérico
(%i7) float(%);
(%o7) 0.7468241328124269
(%i8) ??erf;
0: erf (Error Function)
...
6: nextlayerfactor (Package facexp)
Enter space-separated numbers, `all' or `none': 0;
-- Function: erf (<z>)
The Error Function erf(z) (A&S 7.1.1)
See also flag 'erfflag'.
(%o8) true
Es decir, la respuesta la da en términos de la función de error erf (z) (A&S 7.1.1) donde
la referencia entre paréntesis se refiere al apartado 7.1.1. del manual clásico [2]. En los
apartados §19.1 y §19.2 del manual [1] se pueden encontrar más comandos útiles para la
integración analítica de funciones.
Cuando M AXIMA no puede calcular la integral analíticamente podemos calcularla nu-
méricamente. Dado que dedicaremos un apartado especial a la integración (véase los apar-
tados 8.2 y 8.3) vamos simplemente a mencionar aquí que M AXIMA cuenta con el paquete
quadpack que tiene implementado una serie de reglas de cuadratura (véase también el
comando romberg). Este paquete tiene muchísimas opciones así que nos restringiremos
al comando quad_qag. que permite calcular el valor de la integral de una función en un
intervalo acotado quad_qag. Su sintaxis es
El primer elemento de la salida es casi el valor real 1/3 de la integral con una precisión de
10−15 (como nos indica el segundo elemento) y el programa ha necesitado 31 iteraciones
y a culminado sin errores.
Lo mismo podemos hacer con las dos integrales que vimos antes. Por ejemplo, para la
que nos dio como salida la función de error tenemos
Más adelante, como ya mencionamos, volveremos a discutir sobre este tema, no obs-
tante el lector interesado puede consultar en los apartados §19.3 y 19.4 del manual de
M AXIMA [1] una descripción del paquete QUADPACK que contiene distintas funciones para
el cálculo numérico de integrales de una variable.
Vamos ahora a aprender como definir funciones a partir de las salidas de M AXIMA. Por
ejemplo, definamos la función int(x) como la salida de la orden integrate
(%o12) kill(all)$
(%i1) int(x):=integrate(x+2/(x-3),x);
(%o1) int(x):=integrate(x+2/(x-3),x)
(%i2) int(x);
(%o2) 2*log(x-3)+x^2/2
Nótese que M AXIMA nos previene que hay valores para los cuales la función int(x) no está
definida. Además podemos comprobar que la derivada de int(x) es precisamente nuestra
función de partida:
(%i4) diff(int(x),x,1);
(%o4) x+2/(x-3)
Hay hay que ser cuidadoso a la hora de trabajar con las funciones definidas a partir
de las salidas de M AXIMA. El siguiente ejemplo muestra que no siempre M AXIMA funciona
bien:
¿Qué es lo que está ocurriendo? Como se ve, cuando definimos la función int(x) me-
diante := en la entrada %18, su salida es exactamente la misma que la entrada. La razón es
que cuando usamos la definición := lo que hace M AXIMA es asignarle a int(x) la orden co-
rrespondiente pero sin ejecutarla y sólo lo hace cuando se intenta evaluar la función. Este
tipo de definiciones se les suele llamar definiciones o asignaciones diferidas. Así, al escribir
int(1) M AXIMA intenta sustituir la x por 1 en la expresión integrate(x+2/(x-3),x,0,1),
lo que causa el error ya que x es una variable de integración que no podemos cambiar por
1, ya que no tiene sentido la operación.
Veamos otra forma diferente de proceder: la definición o asignación inmediata que lo
que hace es realizar todas las operaciones indicadas y asignar el resultado final a nuestra
función. Para este tipo de definiciones M AXIMA usa el comando define cuya sintaxis es8
siendo f la función a definir cuyas variables son x_1,...,x_n y expr es la expresión que
define nuestra función. Así, por ejemplo, podemos definir la siguiente función:9 :
(%i8) define(intprim(x),integrate(x+2/(x-3),x));
(%o8) intprim(x):=2*log(x-3)+x^2/2
lo que nos permite, efectivamente, usar la salida de M AXIMA para definir la nueva función
intprim, que ahora no nos produce ningún error al evaluarla en 1.
(%i9) intprim(1);
(%o9) 2*log(-2)+1/2
(%i10) intprim(1)-intprim(0);
(%o10) 2*log(-2)-2*log(-3)+1/2
(%i11) %-vnum1;
(%o11) 2*log(3)-2*log(2)+2*log(-2)-2*log(-3)
(%i12) rectform(%);
(%o12) 0
que como vemos es precisamente el caso. Además define también permite usar las fun-
ciones que hemos definido antes
(%i15) define(fun(x),int(x)+sin(x));
(%o15) fun(x):=sin(x)+x^2/2+2*log(x-3)
(%i16) fun(1);
(%o16) sin(1)+2*log(-2)+1/2
Esta forma de definir una función junto con la anteriormente usada mencionada := se denominan en
8
Está claro que las dos formas anteriores de definir funciones son muy distintos por lo
que tenemos que ser cuidadosos a la hora de elegir el modo de hacerlo. Suele dar menos
problemas la asignación inmediata pero puede haber situaciones donde sea conveniente
utilizar la forma diferida.
Como mencionamos antes, una opción muy interesante que tiene M AXIMA es que se
pueden hacer suposiciones sobre las variables (ver página 16). Por ejemplo si pedimos a
M AXIMA que calcule la integral
(%i17) kill(all)$
(%i1) integrate (x^a*%e^(-x), x, 0, inf);
"Is "a+1" positive, negative or zero?"p;
(%o1) gamma(a+1)
este nos pregunta si la a es positiva, negativa, etc. Al responder nos da la solución (¿pre-
guntar a M AXIMA qué significa gamma?). Si sabemos de antemano que, por ejemplo, la a
es positiva, etc. podemos usar el comando assume, concretamente en este caso vamos a
asumir que a > −1:
(%i4) ??gamma;
Finalizaremos este apartado con algunos otros ejemplos sencillos
(%i10) facts();
(%o10) [a>1,b>1]
sin embargo lo vuelve a preguntar.
28
1 00 1
Pn (x, x0 ) = f (x0 ) + f 0 (x0 )(x − x0 ) + f (x0 )(x − x0 )2 + · · · + f (n) (x0 )(x − x0 )n + · · ·
2! n!
es decir, el comando taylor(f(x),x,x0,n) devuelve la serie de Taylor alrededor del punto
x0 truncada hasta el orden n. Por ejemplo
(%i1) taylor(%e^x,x,0,5);
(%o1)/T/ 1+x+x^2/2+x^3/6+x^4/24+x^5/120+...
Si queremos el polinomio de Taylor (o sea, eliminar formalmente los . . . ) hay que usar
el comando taytorat(expr) que devuelve la forma racional de la expresión expr.
Hay que destacar que M AXIMA puede trabajar formalmente con series de potencias
infinitas. Para ello cuenta con el comando powerseries(f(x),x,x0) que devuelve la serie
de potencias de f alrededor del punto x0 .
(%i2) powerseries(%e^x,x,0);
(%o2) sum(x^i1/i1!,i1,0,inf)
(%i3) sere:niceindices(%);
(%o3) sum(x^i/i!,i,0,inf)
(%i4) ser:niceindices(powerseries(1/(1+x),x,0));
(%o4) sum((-1)^i*x^i,i,0,inf)
(%i5) integrate(ser,x);
(%o5) sum(((-1)^i*x^(i+1))/(i+1),i,0,inf)
(%i6) diff(%,x);
(%o6) sum((-1)^i*x^i,i,0,inf)
Otro comando relacionado con las series de potencias es pade. Su sintaxis es:
Su salida es una lista con todas las funciones racionales pm (x)/qn (x) (pm y qn polino-
mios de grado a lo más m y n, respectivamente) que tienen el mismo desarrollo de Taylor
a0 + a1 x + · · · + aN xN + · · · dado y en las que la suma de los grados del numerador
m (grado_numer) y denominador n (grado_denom) es menor o igual que el orden N de
truncamiento de la serie de potencias. Los parámetros grado_numer y grado_denom son
los grados máximos que pueden tener los polinomios numerador pm y denominador qn ,
respectivamente. Además, en el caso cuando la suma de los grados del numerador y de-
nominador de la fracción coincide con el orden de truncamiento de la serie (n + m = N )
la salida coincide con el aproximante de Padé de la función, normalmente denotados por
[m, n].
Comenzamos con el ejemplo de una serie de potencias
R. Álvarez Nodarse Introducción a M AXIMA CAS 29
(%i7) kill(all)$
(%i1) ser: taylor(1+2*x+3*x^2+4*x^3+5*x^4, x, 0, 4);
(%o1) 1+2*x+3*x^2+4*x^3+5*x^4+...
(%i2) pade(ser,1,1);
(%o2) []
La lista nula [] de la salida implica que no existe ninguna función racional del tipo
p1 (x)/q1 (x) con el mismo desarrollo que el dado, así que aumentaremos el grado de los
polinomios pm y qm :
(%i3) pade(ser,2,2);
(%o3) [1/(x^2-2*x+1)]
(%i4) pade(ser,3,1);
(%o4) [-(x^3+2*x^2+3*x+4)/(5*x-4)]
(%i5) pade(ser,1,3);
(%o5) [1/(x^2-2*x+1)]
(%i6) pa:pade(ser,4,4);
(%o6) [1/(x^2-2*x+1),-(x^3+2*x^2+3*x+4)/(5*x-4),5*x^4+4*x^3+3*x^2+2*x+1]
(%i7) wxplot2d([ser,pa[1],pa[2]],[x,-1.2,1.2],[y,0,5],
[legend,"taylor","pade1","pade2"])$
(%t7) (Graphics)
Nótese que en este último caso, entre las tres salidas de M AXIMA, tenemos un polino-
mio que coincide con la serie hasta el orden de truncamiento de la misma. La gráfica la
podemos ver en la figura 2.5 (izquierda).
14 Taylor 1 cos(x)
Aproximación 1 Pade
Aproximación 2
12
0.5
10
8
0
Y
4 -0.5
2
-1
0
-1 -0.5 0 0.5 1 -3 -2 -1 0 1 2 3
X X
(%i10) wxplot2d([cos(x),pa[1]],[x,-%pi,%pi],[y,-1.1,1.1],
[legend,"cos(x)","pade"])$
(%t10) (Graphics)
En este caso como hemos elegido n + m = N tenemos el aproximante de Padé [4, 4] del
cos(x). La gráfica la está representada en la figura 2.5 (derecha) y como se ve ambas
curvas son prácticamente idénticas en el intervalo [−π, π].
Como ejercicio encontrar los aproximantes de la la función sin(x) con 8 términos en su
serie de Taylor. Para este caso, encontrar el aproximante de Padé [4, 4]. Mostrar que ocurre
si calculamos el aproximante con m = n = 5. Representar gráficamente los resultados.
Pasemos a estudiar el caso de la función exponencial f (x) = ex .
(%i11) kill(all)$
(%i1) f(x):=exp(x);
ser:taylor(f(x),x,0,4);
pa:pade(ser,2,2);
plot2d([f(x),pa[1]],[x,-2,2],[y,0,8],[legend,"exp(x)","pade"])$
plot2d([f(x),pa[1]],[x,-2,4],[y,0,20],[legend,"exp(x)","pade"])$
(%o1) f(x):=exp(x)
(%o2) 1+x+x^2/2+x^3/6+x^4/24+...
(%o3) [(x^2+6*x+12)/(x^2-6*x+12)]
(%t4) (Graphics)
plot2d: some values were clipped.
(%t5) (Graphics)
Como vemos de las gráficas (ver figura 2.6) tenemos una aproximación muy buena con el
aproximante de Padé [2, 2] en el intervalo [−2, 2], no así en [−2, 4] donde se ve a simple
vista que el aproximante se aleja bastante del valor de la función. Calculemos
Rb x a conti-
nuación el error en norma L en ambos intervalos mediante la fórmula a (e − r(x))2 dx,
2
(%i8) f(x):=exp(x);
ser:taylor(f(x),x,0,8);
pa:pade(ser,4,4);
wxplot2d( [f(x),pa[1]],[x,-2,5],[y,0,50],[legend,"f(x)","pade"])$
er02:quad_qag ( (exp(x)-pa[1])^2,x,-2,2,3,'epsrel=1d-10);
(%o8) f(x):=exp(x)
(%o9) 1+x+x^2/2+x^3/6+x^4/24+x^5/120+x^6/720+x^7/5040+x^8/40320+...
(%o10) [(x^4+20*x^3+180*x^2+840*x+1680)/(x^4-20*x^3+180*x^2-840*x+1680)]
(%t11) (Graphics)
(%o12) [2.405645817987696*10^-9,2.67080337622316*10^-23,61,0]
R. Álvarez Nodarse Introducción a M AXIMA CAS 31
20
Taylor Taylor
Padé [2,2] 200 Padé [4,4]
15
150
10
Y
Y
100
5 50
0 0
-2 -1 0 1 2 3 4 -2 -1 0 1 2 3 4 5 6
X X
Figura 2.6: Aproximantes de Padé [2, 2] (izquierda) y [4, 4] (derecha) de la serie función
exp(x).
Aumentando el intervalo se puede apreciar mejor la diferencia con el caso [2, 2] conside-
rado antes:
(%i13) wxplot2d([f(x),pa[1]],[x,-2,5],[y,0,50],[legend,"f(x)","pade"])$
er04:quad_qag ( (exp(x)-pa[1])^2,x,-2,4,3,'epsrel=1d-10);
(%t13) (Graphics)
(%o14) [0.1078519986905549,1.197397721980963*10^-15,61,0]
En M AXIMA también se pueden definir funciones a trozos. Esto se hace con los opera-
dores lógicos. Por ejemplo, definamos la función
x2
si x ≤ 0,
f (x) =
sen(x) si x > 0.
(%i15) kill(all)$
(%i1) f(x):=if x<=0 then x^2 else sin(x) $
(%i2) f(-1);f(0);f(1);
(%o2) 1
(%o3) 0
(%o4) sin(1)
Si tiene más trozos habrá que combinar más bloques if-then-else. Por ejemplo
x2
si x ≤ 0,
g(x) = sen(x) si 0 < x < π,
2
x sen(x) si x ≥ π.
se escribe
32
(%i5) g(x):=if x<=0 then x^2 else if x <= %pi then sin(x) else x^2*sin(x)$
(%i6) makelist(g(x),x,-3,3,1);
(%o6) [9,4,1,0,sin(1),sin(2),sin(3)]
Aparte de estar definidas a trozos puede ocurrir que nuestra función tome ciertos va-
lores en puntos concretos. Por ejemplo,
sen x
si x 6= 0,
sinc(x) = x
1 si x = 0.
se define por
(%i11) h(x):=if equal(x,0) then %pi else if x<0 then cos(x) else
if x <= %pi then sin(x) else exp(x)$
Para comprobarlo creamos la lista (h(−3), h(−2), h(−1), h(0), h(1), h(2), h(3))
(%i12) makelist(g(x),x,-3,5,1);
(%o12) [cos(3),cos(2),cos(1),%pi,sin(1),sin(2),sin(3),%e^4,%e^5]
donde f1, . . . , fm son las coordenadas de la función vectorial f . Por otro lado, la orden
diff([ f1(x,y) , ... , fm(x,y) ]) calcula el diferencial de cada una de las compo-
nentes.
Como ejemplo consideremos la función f (x, y) = (sin(x) sin(y), x3 y 3 ). Primero calcu-
2
lamos la derivada ∂x∂2 ∂y2 de cada componente y luego el de la función completa:
R. Álvarez Nodarse Introducción a M AXIMA CAS 33
(%i13) kill(all)$
(%i1) diff([sin(x)*sin(y)],x,2,y,2);
(%o1) [sin(x)*sin(y)]
(%i2) diff([x^3*y^3],x,2,y,2);
(%o2) [36*x*y]
(%i3) diff([sin(x)*sin(y),x^3*y^3],x,2,y,2);
(%o3) [sin(x)*sin(y),36*x*y]
jacobian([f1(x1,...,xn),...,fm(x1,...,xn)],[x1,...,xn])
donde f1, . . . , fm son las coordenadas de la función vectorial f y x1, . . . , xm, las corres-
pondientes variables.
(%i4) jacobian([sin(x)*sin(y),x^3*y^3,x^2+y^2],[x,y]);
(%o4) [[cos(x)*sin(y), sin(x)*cos(y)],
[3*x^2*y^3 , 3*x^3*y^2 ],
[2*x , 2*y ]]
∂ 2 f (a) ∂ 2 f (a)
···
∂ 2 x1 ∂xn ∂x1
Hf (a) = .. .. ..
,
. . .
∂ 2 f (a) ∂ 2 f (a)
···
∂x1 ∂xn ∂ 2 xn
(%i5) hessian(sin(x)*sin(y),[x,y]);
(%o5) [[-sin(x)*sin(y),cos(x)*cos(y)],[cos(x)*cos(y),-sin(x)*sin(y)]]
(%i6) hessian(x^3*y^3,[x,y]);
(%o6) [[6*x*y^3,9*x^2*y^2],[9*x^2*y^2,6*x^3*y]]
El comando taylor que vimos anteriormente también nos permite encontrar polino-
mios de Taylor para funciones de varias variables. En este caso la sintaxis es distinta
(%i7) define(f(x,y),x*exp(y)+y*sin(2*x));
(%o7) f(x,y):=x*%e^y+sin(2*x)*y
(%i8) taylor (f(x,y) , [x, y], [0,0], 2)$ expand(%);
(%o9) 3*x*y+x
(%i10) taylor (f(x,y) , [x, y], [0,0], 5)$ expand(%);
(%o11) (x*y^4)/24+(x*y^3)/6+(x*y^2)/2-(4*x^3*y)/3+3*x*y+x
Aparte de lo anterior M AXIMA cuenta con un paquete específico para el cálculo vecto-
rial: el paquete vect. Describamos brevemente como funciona dicho paquete. Lo primero
que hay que destacar es que vect está pensado para trabajar en 2 o 3 dimensiones úni-
camente lo cual, en la mayoría de los casos prácticos, es suficiente. Para realizar cálculos
con vect hay que combinar los nombres de las operaciones con las órdenes express y
ev(·,diff). El resto de operadores definidos en vect son: grad (gradiente), div (diver-
gencia), curl (rotacional), laplacian (laplaciano) y (producto vectorial).
Dados dos vectores v = [a, b, c] y w = [x, y, z] podemos calcular el producto escalar con
la orden v.w, es decir usando como operador de multiplicación el “ . ”. Nótese que si usa-
mos el operador multiplicación “ * ” obtenemos un resultado muy distinto (comprobarlo
como ejercicio). Si queremos calcular el producto vectorial v × w hay que usar el operador
“”.
/* Cálculo vectorial */
(%i12) kill(all)$
(%i1) load(vect)$
(%i2) [a, b, c] . [x, y, z];
(%o2) c*z+b*y+a*x
(%i3) [a, b, c] ~ [x, y, z];
(%o3) [a,b,c] ~ [x,y,z]
(%i4) express(%);
(%o4) [b*z-c*y,c*x-a*z,a*y-b*x]
10
Aquí hemos usado expand para eliminar los puntos suspensivos. Esto en principio se debería poder hacer
con la orden taytorat que mencionamos en el caso de una variable, pero por alguna razón hay versio-
nes de M AXIMA que introducen elementos extraños. En este caso se puede usar la combinación equivalente
rat(ratdisrep(expr)), o bien expand como hemos hecho en este ejemplo.
R. Álvarez Nodarse Introducción a M AXIMA CAS 35
(%i5) arm:x^2+y^2-2*z^2;
(%o5) -2*z^2+y^2+x^2
(%i6) grad(arm);
(%o6) grad(-2*z^2+y^2+x^2)
(%i7) express(%);
(%o7) ['diff((-2*z^2+y^2+x^2),x,1),'diff((-2*z^2+y^2+x^2),y,1),
'diff((-2*z^2+y^2+x^2),z,1)]
(%i8) vv:ev(%,diff);
(%o8) [2*x,2*y,-4*z]
Aunque M AXIMA no ejecute inmediatamente la orden grad si que podemos operar con
~ · ∇f
ella. Por ejemplo encontremos el producto escalar ∇f ~ para nuestra función
(%i9) express(grad(arm).grad(arm));
('diff((-2*z^2+y^2+x^2),z,1))^2+('diff((-2*z^2+y^2+x^2),y,1))^2+
('diff((-2*z^2+y^2+x^2),x,1))^2
ev(%,diff);
(%o10) 16*z^2+4*y^2+4*x^2
(%i11) div(vv);
(%o11) div([2*x,2*y,-4*z])
(%i12) express (%); ev(%,diff);
(%o12) 'diff((-4*z),z,1)+'diff((2*y),y,1)+'diff((2*x),x,1)
(%o13) 0
(%i14) curl(vv);
(%o14) curl([2*x,2*y,-4*z])
(%i15) express (%); ev(%,diff);
(%o15) ['diff((-4*z),y,1)-'diff((2*y),z,1),
'diff((2*x),z,1)-'diff((-4*z),x,1),
'diff((2*y),x,1)-'diff((2*x),y,1)]
(%o16) [0,0,0]
d2 f 2
~ · ∇)f
El laplaciano de una función está definido por ∆f = (∇ ~ = div(gradf ) = d z2
+ dd yf2 +
d2 f
d x2
. Así
(%i28) ev(express(grad(arm2)),diff);
(%o28) [(2*x)/(y^2+x^2),(2*y)/(y^2+x^2),0]
(%i29) div(%);
(%o29) div([(2*x)/(y^2+x^2),(2*y)/(y^2+x^2),0])
(%i30) express(%); ev(%,diff); ratsimp(%);
(%o30) 'diff((2*y)/(y^2+x^2),y,1)+'diff((2*x)/(y^2+x^2),x,1)
(%o31) 4/(y^2+x^2)-(4*y^2)/(y^2+x^2)^2-(4*x^2)/(y^2+x^2)^2
(%o32) 0
En general, podemos comprobar que ∆f = div (grad f ), para ello definimos la depen-
dencia de f usando la orden depends
(%i33) depends(f,[x,y,z]);
y realizamos las operaciones:
(%o33) [f(x,y,z)]
(%i34) ev(express(grad(f)),diff);
(%o34) ['diff(f,x,1),'diff(f,y,1),'diff(f,z,1)]
(%i35) div(%);
(%o35) div(['diff(f,x,1),'diff(f,y,1),'diff(f,z,1)])
(%i36) divgra:express(%);
(%o36) 'diff(f,z,2)+'diff(f,y,2)+'diff(f,x,2)
(%i37) laplacian(f);
(%o37) laplacian(f)
(%i38) lap:express(%);
(%o38) 'diff(f,z,2)+'diff(f,y,2)+'diff(f,x,2)
(%i39) divgra-lap;
(%o39) 0
Como ejercicio probar que ∆~v = div(grad ~v ) cuando ~v = (vx , xy , vz ) es una función
vectorial, i.e., ~v (x, y, z) = (vx (x, y, z), vy (x, y, z), vz (x, y, z)).
Capítulo 3
Comenzaremos con algunos gráficos en dos dimensiones para luego pasar a tres di-
mensiones.
Dado que en el apartado 2.1 vimos el caso más sencillo de la representación de funcio-
nes explícitas vamos a comenzar este apartado viendo como se pueden representar funcio-
nes implícitas. Para ello tenemos el comando implicit_plot del paquete implicit_plot.
Veamos un ejemplo:
(%i1) load(implicit_plot)$
(%i2) wximplicit_plot([x^2=y^3-3*y+1, x^2+y^2=1], [x,-4,4], [y,-4,4])$
La gráfica la podemos ver en la figura 3.1 (izquierda). Vamos ahora a cambiar algunas de
las opciones por defecto que usa M AXIMA al usar implicit_plot, las cuales también son
válidas para otros comandos similares como plot2d.
Por ejemplo, vamos a redefinir los nombres de las funciones usando la opción legend,
vamos a incluir una red de líneas con la opción grid2d y, finalmente, usaremos la opción
same_xy para obligar a M AXIMA a usar la misma escala para los dos ejes coordenados:
37
38
4
función 1
4 3 función 2
x2 = y3-3*y+1
3 y2+x2 = 1 2
2
1
1
0 0
y
y
-1
-1
-2
-2
-3
-4 -3
-4 -3 -2 -1 0 1 2 3 4
x -4
-4 -3 -2 -1 0 1 2 3 4
x
Figura 3.1: La gráfica de la función implícita definida por las ecuaciones x2 = y 3 −3y +1 =
0 y x2 + y 2 = 1 obtenidas en las salidas ( %i5) (izquierda) y ( %i6) —con otras opciones—
(derecha).
Finalmente, dibujamos un gráfico discreto, o sea, a partir de una lista de datos (ver la
gráfica de la derecha en la figura 3.2):
(%i6) N:60$
xx:makelist(2*%pi*j/N,j,1,N)$
yy:makelist(sin(2*%pi*j/N),j,1,N)$
zz:makelist(sin(2*%pi*j/N)+(2*random(2)-1)/20,j,1,N)$
(%i10) plot2d([[discrete,xx,yy],[discrete,xx,zz]],[style,points,lines],
[point_type,diamond], [color,red,blue],[y,-1.1,1.1],grid2d,
[legend,"sin(x)","sin(x)+ruido"])$
(%i11) wxplot2d([[discrete,xx,yy],[discrete,xx,zz],sin(x)],[x,0,2*%pi],
[y,-1.1,1.1],[style,[points,3],[points,2],[lines,2]],
[point_type,bullet,diamond], [color,red,blue,black],
grid2d, [legend,"puntos del sin(x)","sin(x)+ruido","sin(x)"]);
R. Álvarez Nodarse Introducción a M AXIMA CAS 39
circunferencia
1.5 |x|
1 sin(x)
1
sin(x)+ruido
0.5 0.5
0
0
-0.5
-0.5
-1
-1
-1.5
0 1 2 3 4 5 6 7
-1.5 -1 -0.5 0 0.5 1 1.5
x
Figura 3.2: La gráfica paramétrica de una circunferencia junto a la función |x| (izquierda)
y una gráfica a partir de un conjunto discreto de puntos (derecha).
(%i12) kill(all)$
(%i1) load(implicit_plot)$
a:4$
wximplicit_plot((x^2+y^2)^2=2*a^2*(x^2-y^2),[x,-7,7],[y,-6,6],
same_xy,[legend,"implícita"],[ylabel,"y"] )$
(%t3) (Graphics)
(%i4) wxplot2d(sqrt(2)*a*sqrt(cos(2*t)),[t,-7,7],[y,-7,7],[ylabel,"y"],
[xlabel,"x"],[gnuplot_preamble,"set polar"],same_xy,
[legend,"polares"])$
(%t4) (Graphics)
(%i5) wxplot2d([parametric,a*sqrt(2)*cos(t)/(1+sin(t)^2),
a*sqrt(2)*cos(t)*sin(t)/(1+sin(t)^2),[t,-%pi,%pi]],
same_xy,[ylabel,"y"],[xlabel,"x"],[y,-6,6])$
(%t5) (Graphics)
-0.5
-1
0 1 2 3 4 5 6
x
Figura 3.3: Gráfica del sin(x) a partir de puntos y con pequeñas modificaciones aleatorias
usando distintos estilos.
Cuando trabajamos con funciones escalares de dos variables en muy útil poder repre-
sentarlas. M AXIMA también dibuja gráficas 3D con el comando plot3d cuya sintaxis es
muy similar a la de plot2d
plot3d([funcion1,funcion2,...],[variable1,inicio,final],[variable2,inicio,final])
(%i6) kill(all)$
(%i1) f(x,y):= sin(x) + cos(y);
(%i2) wxplot3d(f(x,y), [x,-5,5], [y,-5,5])$
6
6 implícita 6 paramétrica
4
4 4
2
2 2
0 0 0
y
y
0 2 4 6
-2 -2
-2
-4 -4
-4
-6 -6
-6
-6 -4 -2 0 2 4 6 -6 -4 -2 0 2 4 6 -6 -4 -2 0 2 4 6
x x x
Figura 3.4: Las tres gráficas de la lemniscata de Bernoulli. De izquierda a derecha: forma
implícita, en polares y paramétrica.
cos(y)+sin(x)
2
1.5
1
0.5
0
-0.5
-1
-1.5 4
-2 2
-4 0 y
-2 0 -2
x 2 4 -4
donde [elevation,numx] controla el giro del eje z alrededor del x con un ángulo numx y
[azimuth,numz] gira el plano xy obtenido alrededor del nuevo eje z un ángulo numz. La
salida está representada en el gráfico de la derecha de la figura 3.6.
Antes de continuar vamos a mostrar como cambiar los colores de una misma figura.
Como ejemplo vamos a representar la función definida paramétricamente de la siguiente
√ √
forma: x = u cos(v), y = u sin(v) y z = x2 − y 2 :
4
1.8
1.6
3 1.4
1.2 4 2
1
2 3
0.8 1
0.6 2
0.4
1
0.2
0
1
0
0 -0.2 0 y -1
y
-0.4
-0.6 -1 -2
-1 -0.8
-1 -2
-1.2
-2 -1.4 -3
-1.6
-1.8 -4
-3 -4 -3 -2 -1 0 1 2 3 4
-4 x
-4 -3 -2 -1 0 1 2 3 4
x
La gráfica la vemos en la figura 3.7 (izquierda). Nótese que hemos eliminado el nombre
de los ejes y las líneas de superficie. Vamos ahora a definir los colores de la superficie. Hay
√ √
Figura 3.7: La superficie definida por x = u cos(v), y = u sin(v) y z = x2 − y 2 con las
opciones por defecto para los colores (izquierda) y definiendo los colores a usar (centro y
derecha).
dos formas de hacerlo, una usando los colores predefinidos red, green, blue, magenta,
cyan, yellow, orange, violet, brown, gray, black, white, o bien definiéndolos en
números sexagesimales, dos para cada una de las componentes RGB (rojo, verde, azul)
precedidos por el símbolo #. Para ellos hay que definir la opción palette de la forma
[palette, [gradient, color1, ... , colorn]] que define las tonalidades de color de
la superficie siendo el color1 el color de los valores más pequeños de z y colorn el de los
más grandes (si se quieren ver los valores de las z hay que incluir la opción color_bar).
Las dos posibles opciones las tenemos a continuación
[box,false],[elevation,110],[azimuth,23]);
(%i8) wxplot3d([x1,y1,z],[u,0,3], [v,-%pi,%pi],[grid,50,50],
[xlabel,""],[ylabel,""],[legend,false],
[mesh_lines_color,false],
[palette,[gradient,"#dd0000","#b30000","#990033","#000000"]],
[box,false],[elevation,110],[azimuth,23]);
Otra opción muy útil de Máxima es la de exportar los gráficos como ficheros eps (post-
cript encapsulado), pdf o png, por citar algunos de los formatos más comunes. En el primer
caso podemos usar la orden
y en el segundo
que nos genera un fichero pdf con el gráfico en coordenadas polares de la misma en el
directorio de trabajo de M AXIMA.
Lo anterior lo podemos combinar con las opciones de estos comandos para controlar
los nombres de los ejes, títulos, etc. Es importante saber como controlar el tamaño y tipo
de letra. Para ello hay que usar las opciones de GNUPLOT. A modo de ejemplo mostramos
el caso de un gráfico en pdf.
2
4
3 1
rosa polar
2
0
1
0 1 2 3
3*cos(2*t)
-1
0
0 1 2 3
-1 -2
-2 -3
-3
-4
-4 -3 -2 -1 0 1 2 3
-3 -2 -1 0 1 2 3
t r=3 cos(2θ)
Figura 3.8: Gráficas de la rosa polar r(θ) = 3 cos(2θ) con las opciones por defecto (izquier-
da) y con algunas opciones de G NUPLOT (derecha).
Si queremos letras más grandes o más pequeñas cambiamos el último número 24 (font),
size controla las dimensiones y lw (line width) el grosor de las líneas.
Los gráficos obtenidos por estos comandos se pueden ver en la figura 3.8 (ambos están
representados fijando la anchura de los mismos de forma que se puedan ver las diferencias
entre los mismos, como el tamaño de letra, el grosor de la curva, etc.).
La exportación de gráficos también funciona con los comandos implicit_plot y plot3d.
Para más información de las muchas opciones de los comandos plot2d y plot3d es
recomendable consultar el manual [1].
Antes de pasar a ver otros comandos de M AXIMA conviene tener en cuenta que ade-
más de las órdenes para representar funciones plot2d y plot3d discutidas anteriormente,
M AXIMA cuenta también con un paquete específico para representaciones gráficas: el pa-
quete draw1 . Dicho paquete es una potente interfaz para comunicar M AXIMA con Gnuplot
y ha sido desarrollado por Mario Rodríguez Riotorto y es tremendamente versátil. Vamos
a incluir algunos ejemplos sencillos de su uso sin dar una explicación exhaustiva de las
opciones utilizadas ya que en casi todos los casos es fácil de intuir o adivinar la acción de
cada una de ellas. Para más información sobre dicho paquete recomendamos al lector que
consulte el manual [1] así como la web de su desarrollador
http://www.tecnostats.net o http://riotorto.users.sourceforge.net
Antes de comenzar a describir como funciona draw conviene aclarar que cuando se usa
Gnuplot, y no sólo, M AXIMA precisa escribir una serie de archivos temporales. La variable
1
Conviene hacer notar que en actualizaciones de M AXIMA puede ocurrir que algunas de las opciones de
draw dejen de funcionar. Ello podría estar relacionado con el hecho de que draw usa las librerías pgplot
externas a M AXIMA.
R. Álvarez Nodarse Introducción a M AXIMA CAS 45
que controla a donde van a parar dichos ficheros temporales es maxima_tempdir. Por
defecto M AXIMA suele usar el directorio raíz del usuario pero se puede definir el camino
que se quiera. Por ejemplo, maxima_tempdir:"/home/renato/tmp/maxima" define como
directorio de ficheros temporales al directorio /home/renato/tmp/maxima.
Comenzaremos con el comando draw3d para dibujar gráficos en tres dimensiones. Exis-
ten dos formas de invocar este comando: uno es dentro de la propia sesión wxdraw3d y la
otra mediante una ventana exterior de G NUPLOT con draw3d.
Por ejemplo, dibujemos la función f (x, y) = sin(x2 + y 2 ). Para ello usamos el código
(%i9) kill(all)$
(%i1) load(draw)$
(%i2) define(f(x,y),sin(x^2+y^2));
(%o2) f(x,y):=sin(y^2+x^2)
(%i3) wxdraw3d (font="Arial", font_size = 20, view=[83,25],
enhanced3d = false, xu_grid = 100, color = cyan,
explicit(f(x,y), x,-2,2,y,-2,2),
point_type=filled_circle, point_size = 3,color = black,
points([[0,0,0]]), color = red, points([[1,1,f(1,1)]]) )$
De la secuencia anterior quizá la única opción que puede provocar desconcierto es view
cuyos argumentos (dos ángulos) determinan la posición del observador. Si en vez de la
forma integrada wxdraw3d usamos la externa draw3d, podemos de forma análoga al caso
de plot2d interactuar con la gráfica usando el ratón y cambiar la posición del observador,
la cual la podemos ver en la esquina inferior izquierda (ver gráfica 3.9).
Figura 3.9: Ventana externa a WX M AXIMA de G NUPLOT para el gráfico de la salida ( %i3).
En la esquina inferior izquierda vemos la posición angular del observador.
Si queremos exportar la figura anterior como un fichero pdf tenemos que incluir las
siguientes opciones dentro de la orden draw:
46
que determinan el nombre del fichero (se puede incluir la dirección completa si se quiere,
si no M AXIMA lo graba en el directorio por defecto), el tipo de fichero y las dimensiones
en número de puntos. Así, por ejemplo, para producir la figura 3.10 escribimos
En la orden anterior hay una opción que no estaba incluida en la entrada (%i3) y que
es muy útil: xtics=1, ytics=1, ztics=1/2.
Lo que hace la opción xtics es controlar lo que aparece en el eje x (las otras dos
controlan el resto de los ejes de coordenadas). La opción xtics=1 indica que la distancia
entre dos marcas consecutivas en el eje x es de 1 (en el caso del eje z es 1/2). Se pueden
definir por ejemplo los valores que queremos que aparezcan en los ejes enumerándo-
los entre llaves. Así por ejemplo, si incluimos las opciones xtics={-2,-0.75,0.5,1.5},
ztics={-1,0,1} en la entrada (%i3) nos dibujará la misma gráfica pero en el eje x
aparecerán especificados los valores −2, −0,75, 0,5, 1,5 y el eje z los valores −2, 0, 1 a
diferencia de los valores por defecto (ver la figura 3.9) o bien una lista de la forma
{["cadena", valor numerico]} que pone en la posición de valor numerico la expresión
cadena. Por ejemplo, si agregamos a la entrada (%i3) la opción
ytics={["y=2",2],["y=0",0],["y=-2",-2]} obtendremos una gráfica donde en las po-
siciones −2, 0, 2 del eje y aparecerán las expresiones y = −2, y = 0 e y = 2, respectiva-
mente.
Otra formar de exportar el fichero consiste en escribir tras la orden draw la orden
draw_file(terminal = tipo, file_name="nombre") donde tipo puede ser jpg, png, o
pdf, por ejemplo.
Otras opciones para la terminal son jpg o png que graba una figura en formato jpg o
png, respectivamente. Si en vez de una rejilla queremos que M AXIMA dibuje una superficie
coloreada usamos la opción enhanced3d = true. En la figura 3.10 se muestran dos salidas
de draw3d, con las dos posibilidades para la opción enhanced3d. Si queremos eliminar la
barra de colores que sale en la gráfica de la derecha de la figura 3.10 debemos usar la
opción colorbox=false.
En el siguiente ejemplo vamos a dibujar la superficie z = f (x, y) definida por la función
f (x, y) y el plano tangente a la misma en un punto dado (a, b).
R. Álvarez Nodarse Introducción a M AXIMA CAS 47
1
0.8
0.6
1
1 0.5
0.4
0.2
0.5 0
0 0 -0.2
-0.5 -0.5 -0.4
-0.6
-1 -1 -0.8
-1
-2 -3
2 -2 3
-1
1 -1
2
0 0 0
1
0
1 -1 1 -1
2
2 -2 -2
3-3
Figura 3.10: Los gráficos de la función sin(x2 + y 2 ) con la opción enhanced3d = false
(izquierda) y enhanced3d = true (derecha).
(%i5) define(f(x,y),exp(-x^2-y^2));
define(dxf(x,y),diff(f(x,y),x));
define(dyf(x,y),diff(f(x,y),y));
(%o5) f(x,y):=%e^-y^2-x^2
(%o6) dxf(x,y):=-2*x*%e^-y^2-x^2
(%o7) dyf(x,y):=-2*y*%e^-y^2-x^2
Para ello usaremos la ecuación del plano tangente en el punto (a, b) cuya expresión analí-
tica es:
∂f ∂f
z − f (a, b) = (a, b)(x − a) + (a, b)(y − b),
∂x ∂y
Dibujemos
√ ahora el plano tangente a la esfera con centro en (0, 0, 0) y radio 1 en el
punto ( 2/2, 1/2, 1/2) con su correspondiente vector normal (ver figura 3.11 derecha).
2
1 1.5
1
0.5 0.5
0 0
-0.5
-2
-1
2
x 0 1 -1
1 0 -0.5 1
-1 y 0 0.5
2 -2 0.5 0
1 -0.5
-1
Figura
p 3.11: Los gráficos de las funciones z = exp(−x2 − y 2 ) (izquierda) y z =
1 − x2 − y 2 (derecha)√con sus correspondientes planos tangentes en los puntos
(1/2, 1/2, exp(−1/2)) y ( 2/2, 1/2, 1/2), respectivamente.
f(x,y) f(x,y)
2 4
1 3
2
0 1
z -1 z 0
-2 -1
-2
-3 -3
-4 -4
4 4
3 3
2 2
1 1
-3 0 -4 -3 0
-2 -1 y -2 -1 -1 y
-1
0 -2 0 1 -2
1 -3 2 -3
x 2 x 3
3 -4 4 -4
Figura 3.12: Los gráficos del elipsoide x2 + 2y 2 + z 2 = 16 con x ∈ [−3, 3], y ∈ [−4, 4] y
z ∈ [−4, 2] (izquierda) y con x ∈ [−4, 4], y ∈ [−4, 4] y z ∈ [−4, 4] (derecha).
Veamos ahora algunos ejemplos del comando draw2d para gráficos en dos dimensiones.
(%i16) kill(all)$
(%i1) load(draw)$
(%i2) f(x):=(2*x)/(x^2+1)$
(%i3) wxdraw2d(explicit(f(x),x,-8,8));
(%i4) wxdraw2d(grid = true, axis_top = false, axis_right = false,
yrange = [-1,1], key = "f(x)", line_width = 3,
explicit(f(x),x,-8,8),dimensions = [800,600]);
El primero es la típica orden para dibujar el gráfico de una función f (x) usando las op-
ciones por defecto de gnuplot. En la segunda, hemos redefinido algunas de las opciones
50
f(x,y)
12
11
10
9 1
z 8
7 0.5
6
5
4 0
-0.5
-2 -1 1
-1.5
-1 0.5
-0.5 0
0 2
1.5
x 0.5 1 -1 -0.5
0.5 -0.5 0
1 0 0.5
1.5
-0.5 1 -1
-1 y
2 -2 -1.5
Figura 3.13: El gráfico de la función curva definida por z = f (x, y) = (x + y)2 + 1 cuando
las variables x e y están sujetas a la condición x2 + y 2 = 4 (izquierda) y la figura de
revolución definida por la función f (x) = x (derecha).
de gnuplot. Como hemos dicho antes es conveniente leer la documentación de draw para
más detalles sobre las mismas.
Con draw2d se pueden dibujar varias funciones en un mismo gráfico —ver figura 3.14
(izquierda)—
Un opción interesante que vemos son las distintas opciones de líneas, lo cual es convenien-
te si el gráfico se va a visualizar en blanco y negro. Dicha opción es line_type y las posi-
bilidades son para todas los terminales solid y dots. También es posible usar las opciones
dashes, short_dashes, short_long_dashes, short_short_long_dashes y dot_dash, pero
no están disponibles en los terminales png, jpg y gif.
También se pueden mezclar distintos tipos de gráficos: explícitos, implícitos y paramé-
tricos:
Aquí nticks controla en número de puntos que se dibujan en dos dimensiones con las
órdenes explicit, parametric, polar y en tres con parametric. La gráfica resultante
se puede ver en la figura 3.14 (derecha).
implícita
4 explícita
paramétrica
0.5
0
0
-0.5 -2
-4
-1
0 1 2 3 4 5 6 -2 0 2 4 6
Podemos dibujar el área bajo la curva de una función dada. Por ejemplo, el área bajo
la curva de la función f (x) que definimos antes en el intervalo [1, 5] —ver figura 3.15
(derecha)—
(%i8) f1(x):=2*x^2-5*x+3;
f2(x):=-8*x^2-x+30;
[x1,x2]: map('rhs,solve(f1(x)=f2(x),x));
(%o10) [−sqrt(274)−2/10,(sqrt(274)+2)/10]
(%i11) wxdraw2d(fill_color = grey,font="Arial", font_size = 16,
filled_func = f2, line_width = 5, dimensions = [800,600],
2
El comando map lo describiremos en detalle más adelante (página 99).
52
1
30 f(x) f(x)
g(x)
20 0.5
10
0
Y
0
Y
-10 -3 -2 -1 0 1 2 3
-0.5
-20
-30
-1
-40 -8 -6 -4 -2 0 2 4 6 8
X X
Figura 3.15: Región entre las curvas f (x) = 2x2 −5x+3 y g(x) = −8x2 −x+30 (izquierda)
y el área bajo la función f (x) = (2x)/(x2 + 1) en [2, 5] (derecha).
region (expr,var1,minval1,maxval1,var2,minval2,maxval2)
que dibuja una región del plano definida por las desigualdades descritas en expr. Como
ejemplo veamos la región entre las mismas dos funciones de antes f (x) = 2x2 − 5x + 3 y
g(x) = −8x2 − x + 303
donde en la primera solo dibujamos la región, y en la segunda incluimos las dos funciones
(ver figura 3.16). Además hemos usado una opción interesante de M AXIMA que permite
guardar en una variable la propia gráfica. Eso se hace con el comando gr2d (también se
puede hacer con gráficas 3D usando gr3d). Las gráficas así guardadas luego se pueden
reutilizar como mostraremos más adelante.
Una opción interesante del paquete draw es que permite hacer una matriz (array) de
gráficas.
Por ejemplo, vamos a dibujar una rosa polar y una espiral hiperbólica
3
Aquí hemos usado el operador lógico and que discutiremos con más detalle en la página 159.
R. Álvarez Nodarse Introducción a M AXIMA CAS 53
40 40
30 30
20 20
10 10
0 0
-10 -10
-20
-20
-30
-30
-40
-40
-3 -2 -1 0 1 2 3 -3 -2 -1 0 1 2 3
Figura 3.16: Región entre dos curvas f (x) = 2x2 −5x+3 y g(x) = −8x2 −x+30 (izquierda)
y dicha región junto a las funciones (derecha).
Incluso podemos representar tres, cuatro, etc. (la última se representa en la figura
3.17):
4 4
2 2
0 0
-2 -2
-4 -4
-4 -2 0 2 4 -4 -2 0 2 4
20 20
10 10
0 0
-10
-10
-20
-20
-30
-30
-40
-40
-3 -2 -1 0 1 2 3 -3 -2 -1 0 1 2 3
(%i1) p(x,k):=taylor(exp(x),x,0,k)$
(%i2) makelist(p(x,k),k,1,5)$
tay:append([exp(x)],%)$
makelist(concat("pol. Taylor orden ",k),k,0,4)$
legenda: append([legend,"exp(x)"],%)$
(%i6) wxplot2d(tay,[x,-2,1],[y,-1,4],legenda,[xlabel,""])$
(%t6) << Graphics >>
(%i7) load(draw)$
colors : ['green,'orange,'red,'magenta,'blue,'brown]$
dd:makelist([key=concat("Pol. Taylor de orden ",k),color=colors[k],
explicit(p(x,k),x,-2,1)],k,1,5)$
R. Álvarez Nodarse Introducción a M AXIMA CAS 55
4
exp(x)
3
pol. Taylor orden 1 Pol. Taylor de orden 1
3 pol. Taylor orden 2 Pol. Taylor de orden 2
2.5
pol. Taylor orden 3 Pol. Taylor de orden 3
pol. Taylor orden 4 Pol. Taylor de orden 4
2 2 Pol. Taylor de orden 5
pol. Taylor orden 5
exp(x)
1.5
1
1
0 0.5
0
-1
-2 -1.5 -1 -0.5 0 0.5 1 -0.5
-1
-2 -1.5 -1 -0.5 0 0.5 1
Figura 3.18: Gráficas de los polinomios de Taylor p1 (x, 0), . . . , p5 (x, 0) de la función ex
alrededor del cero usando plot2d (izquierda) y draw2d (derecha).
Finalmente, debemos mencionar que podemos eliminar los distinos ejes usando las
órdenes axis_left=false, axis_right=false, axis_top=false, axis_bottom=false,
xtics=false, ytics=false.
Veamos a continuación como crear una animación con M AXIMA. Como ejemplo dibuje-
mos la secuencia de aproximación de la exponencial ex mediante los sucesivos polinomios
de Taylor hasta orden 9.
La primera forma es muy simple, lo que se hace es representar una serie de gráficas,
una a continuación de la otra, con draw combinadas con un ciclo para retrasar la visuali-
zación de cada uno:
Aquí hemos usado un comando muy cómodo para definir funciones dentro de M AXIMA: el
comando block cuya sintaxis es
56
En en caso que no funcione este tipo de terminal (no todos los sistemas la tienen instalada)
podemos combinar la creación de varios ficheros png y su conversión en un gif animado.
La siguiente secuencia nos crea la animación deseada y la salva en el directorio animado:
R. Álvarez Nodarse Introducción a M AXIMA CAS 57
3
3 exp(x)
exp(x)
pol. Taylor orden 3 2.5 Pol. taylor de orden 3
2.5
2
2
1.5 1.5
1 1
0.5 0.5
0 0
-0.5
-2 -1.5 -1 -0.5 0 0.5 1 -0.5
x
-2 -1.5 -1 -0.5 0 0.5 1
Figura 3.19: Fotograma para k=3 de las animaciones de las salidas ( %i13) con
with_slider (izquierda) y ( %i14) con with_slider_draw (derecha), respectivamente.
Veamos una animación 3D. Para ello usaremos la orden with_slider_draw3d y re-
presentaremos una partícula que se mueve por la trayectoria paramétrica definida por
(2 cos u, 2 sin u, u). Es conveniente fijar todos los parámetros relacionados con la dimen-
sión para que la animación no cambie la escala ni el ángulo de visión en cada una de
sus gráficas (fotogramas). Así, fijamos el ángulo de visión con view, y seleccionamos el
rango de las variables con xrange, yrange, zrange. En la primera animación vemos la
partícula moverse en el espacio donde hemos dejado los ejes coordenados visibles
(%i17) kill(all)$
(%i1) load(draw)$
(%i2) with_slider_draw3d(k , /* variable de cambio */
makelist(i,i,0,30,1), /* lista de valores de la variable */
color = blue, point_type=filled_circle, point_size =2,
points([[2*cos(2*%pi*k/10),2*sin(2*%pi*k/10), 2*%pi*k/10 ]]),
color = magenta, nticks = 50, xtics = 1, ytics = 1, ztics = 10,
line_width=3, zrange=[0,20], xrange=[-2.1,2.1],yrange=[-2.1,2.1],
parametric(2*cos(u),2*sin(u),u,u,0,2*%pi*k/10),
view=[60,60],proportional_axes = xy)$
(%t2) << Graphics >>
20
10
-2
-1
0 2
1
1 0
-1
2 -2
Figura 3.20: Fotograma para k=20 del movimiento de la partícula según la trayectoria
definida por (2 cos u, 2 sin u, u) (con y sin ejes).
En todos los casos donde hemos usado los comandos with_slider, with_slider_draw
y with_slider_draw3d conviene tener en cuenta que la variable que identifica cada foto-
grama (en nuestros ejemplos k) no debe tener asignado previamente ningún valor.
Si queremos crear un gif animado podemos usar la siguiente secuencia, muy similar
a la que ya vimos para el caso 2D:
Como ejercicio dejamos al lector que genere el gif animado eliminando los ejes coor-
denados.
Para terminar esta sección dedicada a la representación gráfica con M AXIMA recomen-
damos al lector visitar la web de Mario Rodríguez Riotorto, desarrollador del paquete
draw entre otros del proyecto M AXIMA: http://www.tecnostats.net donde podrá encon-
trar otros ejemplos interesantes.
Capítulo 4
En este capítulo vamos a discutir otros comandos útiles a la hora de resolver problemas
matemáticos usando M AXIMA.
Comenzaremos con las ecuaciones. Ya hemos visto que el comando solve es capaz de
resolver muchas ecuaciones. Veamos dos muy sencillas. La primera es e2x = 3 que M AXIMA
resuelve sin problemas1
(%i1) solve(exp(2*x)-3=0);
(%o1) [x=log(-sqrt(3)),x=log(3)/2]
(%i2) ec: sin(x)=1;
(%o2) sin(x)=1
(%i3) solve(ec);
solve: using arc-trig functions to get a solution.
Some solutions will be lost.
(%o3) [x=%pi/2]
y nos advierte que puede perder soluciones, como de hecho ocurre pues sen(π/2+2kπ) = 1
para todo k entero. Sin embargo, al intentar resolver la ecuación ex − x − 2 = 0, la salida
es la propia ecuación reescrita
(%i4) solve(exp(x)-x-2=0);
(%o4) [x=%e^x-2]
1
El lector avispado se habrá dado cuenta de que la primera solución que da M AXIMA es algo “rara”. ¿Está
M AXIMA calculando mal? Como pista de lo que ha hecho M AXIMA recomendamos al lector que use la opción
logexpand:super que mencionamos en la página 19. Esto es un ejemplo más de que programa simbólicos
como M AXIMA deben usarse con cierto cuidado y analizando las correspondientes salidas pues, en este caso a
diferencia del ejemplo de la ecuación sen(x) = 1 M AXIMA no nos da ninguna alerta (warning).
59
60
donde además de la ecuación y la variable respecto a la cual hay que resolverla, tenemos
que indicar el inicio y el final del intervalo donde M AXIMA debe buscar la solución. Así,
escribimos
(%i5) find_root(exp(x)-x-2=0,x,0,1);
find_root: function has same sign at endpoints:
mequal(f(0.0),-1.0), mequal(f(1.0),-0.28171817154095)
-- an error. To debug this try: debugmode(true);
Aquí M AXIMA nos indica que no puede resolver la ecuación pues el signo de la función en
los extremos del intervalo coinciden (en este ejemplo ambos son negativos) por lo que su
algoritmo falla (se basa en el teorema de Bolzano para funciones continuas). Una solución
es dibujar la función
(%i6) wxplot2d(exp(x)-x-2,[x,-3,3]);
y a partir del gráfico definir un intervalo adecuado (en nuestro ejemplo el [0, 2] nos val-
dría). Lo anterior nos permite calcular la solución entre en el interior del intervalo (0, 2)
16
14
12
10
8
y
6
4
2
0
-2
-3 -2 -1 0 1 2 3
x
(%i7) find_root(exp(x)-x-2=0,x,0,2);
(%o7) 1.146193220620583
Precisamente para encontrar un intervalo viable que nos permita calcular las raíces de una
ecuación usando la orden find_root son de gran utilidad las posibilidades interactivas del
comando plot2d que comentamos en la página 9 del capítulo 2.
Por otro lado hay que tener cuidado al usar find_root para calcular las raíces ya
que este no tiene por qué encontrar todas las soluciones de la ecuación. Por ejemplo si
2
Algo similar pasa si usamos la orden algsys([exp(x)-x-2=0],[x]) que discutiremos en breve.
R. Álvarez Nodarse Introducción a M AXIMA CAS 61
intentamos resolver la ecuación sen(x) = 1/2 en el intervalo [−7, 7] M AXIMA nos calcula
una única solución cuando en realidad hay siete.
Para resolver ecuaciones numéricamente existen otros dos comandos que conviene co-
nocer y que son newton(expr,x,x0,eps) y mnewton(listafun,listavar,listvalini),
que ejecutan el método de Newton para el cálculo de raíces para ecuaciones (expr=0) y
sistemas de ecuaciones (listafun=[expr1,...,exprN]), respectivamente. En el primer
caso x, x0, eps son la variable, el valor inicial de la misma y la precisión, respectiva-
mente, mientras que en la segunda listavar, listvalin es la lista de las variables y la
lista de sus valores iniciales. En ambos casos hay que cargar previamente los paquetes
“newton1” y “mnewton”, respectivamente. Dejamos como ejercicio que el lector los use el
los ejemplos siguientes:
load(newton1)$
newton (exp(x)-x-2, x, 0.1, 10^(-3));
newton (exp(x)-x-2, x, 0.1, 10^(-16));
load(mnewton)$
mnewton([exp(x)-x-2],[x],[0.1]);
mnewton([exp(x)-y-2,exp(y)+x-1],[x,y],[0.1,1]);
Los comandos find_root, newton y mnewton calculan las soluciones para ecuaciones en
general, no obstante M AXIMA tiene un comando específico para calcular las raíces nu-
méricas reales y complejas de un polinomio: la orden allroots (véase también la orden
realroots).
(%i8) ec1:2*x+3*y-z=1;
(%o8) -z+3*y+2*x=1
(%i9) ec2:3*x-y+z=0;
(%o9) z-y+3*x=0
(%i10) solve([ec1,ec2],[x,y]);
(%o10) [[x=-(2*z-1)/11,y=(5*z+3)/11]]
Como se ve, M AXIMA entiende que z es un parámetro libre y deja la solución en función
del mismo. Si le pedimos que resuelva el sistema respecto a las tres variables entonces
introduce las constantes que necesite (en este caso %r1) en el caso de que el sistema sea
indeterminado (como el del ejemplo que nos ocupa). Así, la solución queda definida en
función del parámetro independiente %r1
(%i11) solve([ec1,ec2],[x,y,z]);
(%o11) [[x=-(2*%r1-1)/11,y=(5*%r1+3)/11,z=%r1]]
(%i12) ec3:x+y+z=1;
(%o12) z+y+x=1
(%i13) solve([ec1,ec2,ec3],[x,y,z]);
(%o13) [[x=0,y=1/2,z=1/2]]
(%i14) solve([x^2+y^2=1,x-y=2],[x,y]);
(%o14) [[x=-(sqrt(2)*%i-2)/2,y=-(sqrt(2)*%i+2)/2],
[x=(sqrt(2)*%i+2)/2,y=(sqrt(2)*%i-2)/2]]
(%i15) solve([x^3+y^2=1,x-y=2],[x,y]);
(%o15) (%o25) [[x=0.5033313284659912*%i+0.903150358370507,
y=0.5033313284659912*%i-1.096849641629493],
[x=0.903150358370507-0.5033313284659912*%i,
y=-0.5033313284659912*%i-1.096849641629493],
[x=-2.80630068621335,y=-4.806301050175029]]
o bien nos da error en caso de no poder resolverlo de ninguna de las dos formas
(%i16) solve([x^3+y^2=1,sin(x)-y=2],[x,y]);
algsys: tried and failed to reduce system to a polynomial
in one variable; give up.
-- an error. To debug this try: debugmode(true);
Además, si nos fijamos en el mensaje que nos da M AXIMA vemos que cuando solve no pue-
de calcular analíticamente la solución entonces pasa al cálculo numérico usando algsys.
De hecho algsys es junto a linsolve otra de las órdenes que tiene M AXIMA para resolver
sistemas aparte de la orden solve. La sintaxis de dichas órdenes son
algsys([ecuaciones],[variables]) y linsolve([ecuaciones],[variables])
(%i17) kill(all)
(%i1) solve(x^7+2*x+1);
(%o1) [0=x^7+2*x+1]
(%i2) algsys([x^7+2*x+1=0],[x]);
(%o2) [[x=0.07635557774869883-1.140946142049927*%i], ...
,[x=-0.4962920707358813]]
Si solo nos interesan las soluciones reales conviene saber que algsys reconoce la varia-
ble global realonly que cuando toma el valor true no tendrá en cuenta las soluciones
complejas. Por ejemplo, la misma salida anterior con la opción realonly:true sería
(%o2) [[x=-0.4962920707358813]]
R. Álvarez Nodarse Introducción a M AXIMA CAS 63
(%i3) eq:[x+2*y+3*z=a,3*x+2*y+z=-a,x-y+z=a]$
(%i4) solve(eq,[x,y,z]);
(%o4) [[x=-a/4,y=-a/2,z=(3*a)/4]]
(%i5) linsolve(eq,[x,y,z]);
(%o5) [x=-a/4,y=-a/2,z=(3*a)/4]
(%i6) linsolve(eq,[x,y,z,a]);
(%o6) [x=-%r4/4,y=-%r4/2,z=(3*%r4)/4,a=%r4]
Nótese que la salida depende de cuales son las incógnitas, así el mismo sistema eq tiene
soluciones distintas si se resuelve respecto a las variables x,y,z o respecto a x,y,z,a.
Existe otro comando que conviene tener en cuenta: eliminate y cuya sintaxis es
eliminate ([eq1,eq2,...,eqn],[x1,x2,...,xk])
que intenta eliminar las variables x1,. . . , xk de las ecuaciones eq1,. . . , eqn (k < n). Por
ejemplo:
(%i7) eq:[x-y=0,x^2+y^2=1];
(%o7) [x-y=0,y^2+x^2=1]
(%i8) eliminate(eq,[x]);
(%o8) [2*y^2-1]
(%i9) eliminate(eq,[y]);
(%o9) [2*x^2-1]
Aquí vemos que ratsimp no puede simplificar las expresiones que están en las distintas
raíces. Si tenemos expresiones que involucran radicales, exponenciales y logaritmos con-
viene usar en vez de ratsimp la orden radcan.
64
(%i3) radcan( % );
(%o3) -2/sqrt(x+1)
(%i4) radcan([sqrt(x+1)/sqrt(x^2-1),log(x^2-2*x+1)/log(x-1)]);
(%o4) [1/sqrt(x-1),2]
(%i8) ratsimp((log(x+x^2)-log(x))^a/log(1+x)^(a/2));
(%o8) (log(x^2+x)-log(x))^a/log(x+1)^(a/2)
(%i9) fullratsimp((log(x+x^2)-log(x))^a/log(1+x)^(a/2));
(%o9) (log(x^2+x)-log(x))^a/log(x+1)^(a/2)
(%i10) radcan((log(x+x^2)-log(x))^a/log(1+x)^(a/2));
(%o10) log(x+1)^(a/2)
Para la segunda, tanto ratsimp como fullratsimp solo simplifican la parte racional como
era de esperar
(%i14) radcan(expr2);
(%o14) sin((x+1)^(3/2)/(2*sqrt(x-3)*x))
R. Álvarez Nodarse Introducción a M AXIMA CAS 65
Nótese que si usamos radcan para simplificar la expresión de la entrada (%i5) obtenemos
el mismo resultado que el de la orden fullratsimp
(%i15) radcan(expr1);
(%o15) x^a-1
En ocasiones las órdenes ratsimp y fullratsimp no son de ayuda como es el caso del
siguiente ejemplo
En este caso es mejor usar la orden xthru(expr) que combina todos los términos de expr
(la cual debe ser una suma) sobre un común denominador sin expandir productos ni
sumas elevadas a exponentes. Así se tiene
Antes de continuar debemos mencionar que la forma de simplificar que tiene radcan
está controlada por la variable radexpand con valores true (por defecto), all y false. Co-
mo ejemplo mostramos a continuación distintas salidas de la ordenradcan para distintos
valores de la variable radexpand:
Antes de pasar a discutir otros comandos debemos mencionar que el comando radcan
consume muchos recursos por lo que muchas veces es conveniente intentar simplificar
lo máximo posible antes de usarlo. Se recomienda al lector consultar la sección 14 so-
bre polinomios de manual [1] para más detalles sobre la manipulación de expresiones
polinómicas y racionales así como la sección 9 sobre simplificación.
Aparte de las órdenes discutidas anteriormente M AXIMA cuenta con comandos específi-
cos para la manipulación de expresiones trigonométricas. Entre ellos tenemos a trigsimp,
trigreduce y trigrat.
66
(%i30) kill(all)$
(%i1) expr:ratsimp( 4/(1-%e^(2*b))*sinh(b)^2 );
(%o1) -(4*sinh(b)^2)/(%e^(2*b)-1)
(%i2) exponentialize(%);
(%o2) -(%e^b-%e^(-b))^2/(%e^(2*b)-1)
(%i3) ratsimp(%);
(%o3) -%e^(-2*b)*(%e^(2*b)-1)
(%i4) A*cos(theta+phi+psi);
(%o4) cos(theta+psi+phi)*A
(%i5) expand(%);
(%o5) cos(theta+psi+phi)*A
(%i6) trigexpand(%);
(%o6) (-cos(phi)*sin(psi)*sin(theta)-sin(phi)*cos(psi)*sin(theta)-
sin(phi)*sin(psi)*cos(theta)+cos(phi)*cos(psi)*cos(theta))*A
(%i7) ratsimp(%);
(%o7) ((-cos(phi)*sin(psi)-sin(phi)*cos(psi))*sin(theta)+
(cos(phi)*cos(psi)-sin(phi)*sin(psi))*cos(theta))*A
(%i8) trigreduce(%);
(%o8) cos(theta+psi+phi)*A
Cuando uno trabaja con expresiones trigonométricas conviene tener en cuenta las siguien-
tes opciones:
trigexpandplus (valor por defecto true) que determina si las expresiones del tipo
sin(x + y), y similares, son o no desarrolladas
trigexpandtimes (valor por defecto true) determina si las expresiones del tipo
sin(kx), k ∈ N y similares serán o no desarrolladas,
trigsign (valor por defecto true) que incluye identidades del tipo sin(−x)=− sin(x),
halfangles (valor por defecto, false), que controla si las fórmulas con ángulo mi-
tad serán o no reescritas en términos del ángulo completo.
3
Puede que se necesite ejecutar trigreduce dos veces.
R. Álvarez Nodarse Introducción a M AXIMA CAS 67
Otra opción muy interesante de M AXIMA es que podemos definir el tipo de variable
que estamos usando. Ello se hace con el comando declare (véase el manual [1] para más
detalles sobre este versátil comando). Por ejemplo si hacemos
(%i9) kill(n,m)$
(%i10) [sin (%pi * n), cos (%pi * m), sin (%pi/2 * m), cos (%pi/2 * m)];
(%o10) [sin(%pi*n),cos(%pi*m),sin((%pi*m)/2),cos((%pi*m)/2)]
entonces M AXIMA entiende que n y m son enteros y que además m es par y procede a
simplificar las expresiones.
Las posibilidades de simplificar expresiones con M AXIMA son enormes. Es conveniente
echarle un vistazo a las secciones §9 y §14 del manual [1] antes mencionadas.
Finalmente, mostremos como M AXIMA resuelve desigualdades. Para ello hay que car-
gar el paquete fourier_elim. La sintaxis del comando es
donde [eq1,eq2,...] es una lista de desigualdades lineales y [var1, var, ...], son las
correspondientes variables. Hay algunos casos de desigualdades no lineales que involu-
cran a las funciones valor absoluto, mínimo y máximo, y a algunas expresiones que son
productos o cocientes de términos lineales que también se pueden resolver con esta orden.
Como ejemplo resolvamos algunas desigualdades sencillas (las gráficas se incluyen
como forma de comprobación visual y no las incluiremos aquí):
(%o14) kill(all)$
(%i1) load(fourier_elim)$
(%i2) ineq:(x-1)*(x-2)>0;
fourier_elim([ineq],[x]);
(%o2) (x-2)*(x-1)>0
(%o3) [2<x] or [x<1]
(%i4) wxplot2d([(x-1)*(x-2)], [x,0,3])$
(%i5) ineq1:(x-1/2)*(x-5/2)<=0;
(%o5) (x-5/2)*(x-1/2)<=0
(%i6) fourier_elim([ineq1],[x]);
(%o6) [x=1/2] or [x=5/2] or [1/2<x,x<5/2]
(%i7) wxplot2d([(x-1/2)*(x-5/2)], [x,0,3])$
(%i8) fourier_elim([ineq,ineq1],[x]);
(%o8) [x=1/2] or [x=5/2] or [2<x,x<5/2] or [1/2<x,x<1]
(%i9) wxplot2d([(x-1)*(x-2),(x-1/2)*(x-5/2)], [x,0,3])$
matrix(fila1,fila2,...)
4
Nuevamente hemos usado el operador lógico and que discutiremos con más detalle en la página 159.
R. Álvarez Nodarse Introducción a M AXIMA CAS 69
(%i1) A:matrix([1,2],[2,1]);
(%o1) matrix([1,2],[2,1])
(%i2) B:matrix([1,-1,4],[3,2,-1],[2,1,-1]);
(%o2) matrix([1,-1,4],[3,2,-1],[2,1,-1])
Si se sabe una expresión para generar cada elemento se puede definir de forma parecida
a las funciones. En primer lugar se definen cada uno de los elementos de la matriz. En
nuestro ejemplo construiremos la matriz C cuyos elementos son ci,j = (i + j)2 .
(%i3) C[i,j]:=(i+j)^2;
(%o3) C[i,j]:=(i+j)^2
donde debemos especificar el número de filas y columnas. Así para generar la matriz C de
4 × 3 usamos
(%i4) D:genmatrix(C,3,4);
(%o4) matrix([4,9,16,25],[9,16,25,36],[16,25,36,49])
El comando submatrix nos permite quedarnos con cualquier submatriz. Por ejemplo
si de la matriz D anterior queremos eliminar la fila 2 y las columnas 1 y 4 escribimos
(%i5) E:submatrix(2,D,1,4);
(%o5) matrix([9,16],[25,36])
En general la sintaxis es
(%i6) A.E;
(%o6) matrix([59,88],[43,68])
Hay que tener cuidado pues A ∗ E también nos devuelve una salida que no tiene nada que
ver con la anterior ( * multiplica elemento a elemento).
(%i7) A*E;
(%o7) matrix([9,32],[50,36])
(%i8) B.D;
(%o8) matrix([59,93,135,185],[14,34,62,98],[1,9,21,37])
(%i9) B*D;
fullmap: arguments must have same formal structure.
-- an error. To debug this try: debugmode(true);
no lo está. Por supuesto que se pueden sumar matrices de las mismas dimensiones
(%i10) A+E;
(%o10) matrix([10,18],[27,37])
(%i11) A-2*E;
(%o11) matrix([-17,-30],[-48,-71])
etc. Otra operación importante es elevar matrices a potencias enteras. Ello se hace con el
comando A^^n donde A es la matriz y n la potencia correspondiente. Es importante tener
en cuenta que el símbolo ^ se repite dos veces. Comprobar como ejercicio la diferencia
entre A^n y A^^n.
Podemos ver la k-ésima columna (o fila) de la matriz A con el comando col(A,k)
(row(A,k)), respectivamente
(%i12) row(D,1);
(%o12) matrix([4,9,16,25])
(%i13) col(D,1);
(%o13) matrix([4],[9],[16])
En el caso de las filas también se puede invocar la orden D[k] donde D es la variable que
estamos usando para definir la matriz cuya fila queremos extraer. En nuestro ejemplo la
orden D[1] daría como resultado la misma salida (%o12) de antes.
Si queremos adicionar columnas o filas se usan los comandos addcol y addrow. Como
ejercicio añadir una fila y una columna a la matriz D anterior (úsese la ayuda de M AXIMA
para ver la sintáis de dichos comandos). Finalmente, podemos extraer el elemento (i, j)
de una matriz D con el comando D[i,j]. Por ejemplo, para extraer los elementos D1,1 y
D3,4 de la matriz D hacemos
(%i16) E;
(%o16) matrix([9,16],[25,36])
(%i17) transpose(E);
(%o17) matrix([9,25],[16,36])
R. Álvarez Nodarse Introducción a M AXIMA CAS 71
(%i18) determinant(E);
(%o18) -76
(%i19) D; rank(D);
(%o19) matrix([4,9,16,25],[9,16,25,36],[16,25,36,49])
(%o20) 3
(%i21) invA:invert(A);
(%o21) matrix([-1/3,2/3],[2/3,-1/3])
(%i22) A.invA;
(%o22) matrix([1,0],[0,1])
(%i23) triangularize(B);
(%o23) matrix([1,-1,4],[0,5,-13],[0,0,-6])
(%i24) triangularize(D);
(%o24) matrix ([4,9,16,25],[0,-17,-44,-81],[0,0,-8,-24])
eigenvalues(matriz) eigenvectors(matriz)
(%i25) eigenvalues(B);
(%o25) [[3,-2,1],[1,1,1]]
(%i26) eigenvectors(B);
(%o26) [[[3,-2,1],[1,1,1]],[[[1,2,1]],[[1,-1,-1]],[[1,-4,-1]]]]
La salida de eigenvalues son dos listas: la primera corresponde a los autovalores distin-
tos de la matriz, y la segunda a la multiplicidad algebraica de los mismos. La salida de
eigenvectors son dos listas, la primera coincide con la salida de eigenvalues, es decir
una lista compuesta por dos listas: la de los autovalores y la de su multiplicidad. La segun-
da lista es la lista de los autovectores correspondientes a cada autovalor. Así, por ejemplo,
en el caso de la matriz B anterior vemos que tiene 3 autovalores distintos cada uno de los
cuales tiene multiplicidad algebraica 1. Como ejercicio comprobar que en ejemplo anterior
efectivamente Bv − λv = 0 para cada uno de los autovalores y autovectores.
No siempre los autovalores son simples. Tal es el caso de la matriz F definida a conti-
nuación
72
(%i27) F:matrix([1,1,0],[0,1,0],[0,2,1]);
(%o27) matrix([1,1,0],[0,1,0],[0,2,1])
(%i28) eigenvalues(F);
(%o28) [[1],[3]]
(%i29) eigenvectors(F);
(%o29) [[[1],[3]],[[[1,0,0],[0,0,1]]]]
(%i30) kill(all)$
( %i1) C[i,j]:= random(10);
D:genmatrix(C,5,5);
(%o1) C[i,j]:=random(10)
(%o2) matrix([6,9,0,8,8],[8,3,9,0,6],[3,2,3,0,9],[9,4,4,5,7],[6,2,1,0,4])
(%o3) eigenvalues(D);
"eigenvalues: solve is unable to find the roots of the characteristic
polynomial."
(%o3) []
Así que tenemos que resolver el problema de forma numérica. Una opción es calcular el
polinomio característico y encontrar sus raíces
para lo cual, hemos usado la orden allroots que mencionamos en el apartado de re-
solución de ecuaciones. El próximo paso sería resolver los sistemas (D − xi I)v = 0,
i = 1, 2, 3, 4, 5, donde I es la matriz identidad cinco por cinco. Vamos a resolverlo para el
caso del primer autovalor (para el resto es análogo) para lo que definimos la matriz M =
D − x1 I donde para generar la matriz identidad I usamos el comando identfor(matriz)
que genera una matriz identidad6 de las mismas dimensiones que matriz:
(%i9) eign1:second(eign[1]);
(%o9) 3.891131442362021*%i+0.8728783161156408
(%o10) M:D-eign1*identfor(D)$ b:[0,0,0,0,0]$
(%i12) eq:M.[x1,x2,x3,x4,x5];
(%o12) matrix([8*x5+8*x4+9*x2+(5.127121683884-3.8911314423620*%i)*x1],
...,[(3.1271216838843-3.8911314423620*%i)*x5+x3+2*x2+6*x1])
(%i14) ratprint:false$
makelist(eq[k][1],k,1,5)$
(%i15) linsolve(%,[x1,x2,x3,x4,x5]);
(%o15) [x1=0,x2=0,x3=0,x4=0,x5=0]
De esta forma descubrimos que linsolve solo nos encuentra la solución trivial. Podemos
usar un comando que contiene el paquete linearalgebra que no está explicado en el
manual: la orden linsolve_by_lu(A,b) que encuentra la solución del sistema Ax = b
mediante la descomposición LU de la matriz cuadrada A:
(%i16) linsolve_by_lu(M,b);
(%o16) [matrix([0],[0],[0],[0],[0]),false]
cuya salida nuevamente es la trivial. ¿Qué hacer? está claro que hay que usar un método
específico para la resolución del problema de autovalores. Para ello M AXIMA cuenta con
la implementación de la librería LAPAC7 (Linear Algebra PACKage) originalmente escrita en
F ORTRAN.
Comenzaremos calculando los autovalores con la orden dgeev. En general dgeev tiene
la siguiente sintaxis
dgeev(matriz,vec-der,vec-izq)
que lo que hace es calculas los autovalores de la matriz matriz y los autovectores por la
derecha cuando vec-der=true, y los autovectores por la izquierda cuando vec-izq=true.
Los autovectores por la derecha son las soluciones no triviales del sistema Avder = λvder
H A = λv H donde v H denota la la
mientras que por lo izquierda lo son del sistema vder der
transpuesta conjugada de v. La salida de dgeev una lista de tres elementos. El primer
elemento es una lista con los autovalores. El segundo elemento es false o la matriz de
autovectores por la derecha. El tercer elemento es false o la matriz de autovectores por
la izquierda. Si escribimos dgeev(matriz) la salida es simplemente la lista de autovalores
seguida de dos false (no muestra las matrices de los correspondientes autovectores). Así,
tenemos
Ahora resolvemos el problema de autovalores por la derecha (nótese que hemos puesto la
opción false para la tercera entrada). La salida la guardamos como lista de tres elementos
por comodidad:
(%i19) [L,Vd,Vi]:dgeev(D,true,false)$
7
Para más detalles visitar su web oficial: http://www.netlib.org/lapack/
74
Comprobamos ahora que la solución es correcta calculando la matriz Avk −λk vk para cada
una de las columnas de la matriz de autovalores. En esta salida mostramos el caso del
tercer autovalor, que al ser complejo nos da soluciones cpmplejas a las que calcularemos
su valor absoluto:
Como vemos las salidas son prácticamente cero (con 16 cifras significativas). Lo anterior
lo podemos incluir en un bucle con la orden for. Dentro de sus muchas opciones, las
cuales conviene consultar en el manual [1, §37], usaremos la siguiente:
for variable valor inicial step incremento thru valor final do orden
1. max que calcula máx i, j(|ai,j |), siendo ai,j los elementos de la matriz (no necesaria-
mente cuadrada) matriz. Nótese que esta función no es una norma matricial.
2. one_norm que calcula el máximo de la suma de los valores absolutos de los elementos
de cada columna.
3. inf_norm que calcula el máximo de la suma de los valores absolutos de los elementos
de cada fila.
Así, por ejemplo podemos calcular los valores del máximo elemento en valor absoluto:
o la norma Frobenius:
En este caso obtenemos un error debido a que los valores para los autovectores tercero y
cuarto son complejos. Para subsanarlo simplemente repetimos la orden tomando primero
valores absolutos:
que como vemos no da la matriz nula. ¿Qué ocurre? pues ya hemos comprobado que el
problema estaba bien resuelto.
La razón, como no, es la no conmutatividad del producto matricial. Hagamos un breve
paréntesis en nuestro estudio para mostrar lo anterior. Para ello definiremos una matriz
general de tres por tres y la multiplicaremos por la izquierda y por la derecha por una
diagonal con elementos distintos:
(%i30) A:matrix([a1,a2,a3],[b1,b2,b3],[c1,c2,c3]);
(%o30) matrix([a1,a2,a3],[b1,b2,b3],[c1,c2,c3])
(%i31) Dd:diag_matrix(d1,d2,d3);
(%o31) matrix([d1,0,0],[0,d2,0],[0,0,d3])
(%i32) Dd.A;
(%o32) matrix([a1*d1,a2*d1,a3*d1],[b1*d2,b2*d2,b3*d2],[c1*d3,c2*d3,c3*d3])
(%i33) A.Dd;
(%o33) matrix([a1*d1,a2*d2,a3*d3],[b1*d1,b2*d2,b3*d3],[c1*d1,c2*d2,c3*d3])
76
(%i34) expand(D.Vd-Vd.Dia);
(%i35) dlange(max,%);
(%o35) 1.77635683940025*10^-14
El paquete lapack tiene otras muchas utilidades como por ejemplo rutinas para resolver
el problema de valores singulares de matrices, descomposición QR de una matriz, entre
otros. Para más detalle el lector puede consultar el manual [1].
Llegados a este punto vale la pena destacar que podemos construir matrices cuyos
elementos sean objetos cualesquiera, por ejemplo, funciones:
(%i30) kill(all)$
(%i1) define(polm(x),matrix([1,x],[x,x^2]));
(%o1) polm(x):=matrix([1,x],[x,x^2])
(%i2) diff(polm(x),x);
(%o3) matrix([0,1],[1,2*x])
aplicarle funciones
(%i4) exp(polm(x));
(%o4) matrix([%e,%e^x],[%e^x,%e^x^2])
Nótese que todas estas operaciones las hace elemento a elemento, lo cual es importante a
tener en cuenta a la hora de trabajar con funciones de matrices que se definen de manera
completamente distinta. Un ejemplo de lo anterior es el cálculo de exponencial de una
matriz que mostraremos en el apartado 6.2.
Para terminar este apartado vamos mencionar algunos otros comandos a tener en
cuenta cuando se trabaja con matrices.
En primer lugar, aunque no es recomendable, podemos introducir una matriz elemento
a elemento interactivamente. Ello se hace con el comando entermatrix(n,m), donde n y
m son las dimensiones de la matriz.
(%i5) kill(all);
(%i1) entermatrix(2,2);
Is the matrix 1. Diagonal 2. Symmetric 3. Antisymmetric 4. General
Answer 1, 2, 3 or 4 : 2;
Row 1 Column 1: 3;
Row 1 Column 2: 4;
Row 2 Column 2: 1;
Matrix entered.
(%oi) matrix([3,4],[4,1])
8
Entenderemos que la derivada de un vector o una matriz es la derivada término a término y lo mismo
con la integración.
R. Álvarez Nodarse Introducción a M AXIMA CAS 77
Nótese que si pedimos a M AXIMA escribir una matriz cuadrada este decide preguntar por
varios tipos especiales de matrices, no así para matrices en general. Probar que ocurre si
queremos introducir una matriz que no sea cuadrada, como por ejemplo, entermatrix(2,3).
Aparte de las matrices diagonales (que construimos con diag_matrix(lista)) y y la
identidad ident que ya hemos usado antes hay otras matrices especialmente importantes
como es el caso de las matrices nulas n × m y las proporcionales a la identidad que se
generan mediante los comandos zeromatrix(n,m) y diagmatrix(n,x), respectivamente
y donde para estas últimas n es el orden de la matriz y x el factor de proporcionalidad:
(%i2) ceroM:zeromatrix(3,2);
(%o2) matrix([0,0],[0,0],[0,0])
(%i3) diagmatrix(2,x);
(%o3) matrix([x,0],[0,x])
Si por ejemplo queremos cambiar la segunda fila de la matriz ceroM basta con definir la
lista correspondiente
Para cambiar una columna podemos usar la idea anterior junto a la operación transposi-
ción:
Otro tipo de matrices de gran importancia son las matrices n × m que tienen un único
elemento no nulo en la posición (i, j) y cuyo valor sea, digamos x. Este tipo de matrices
se puede generar con el comando ematrix(m,n,x,i,j)
(%i11) ematrix(3,2,x,1,2);
(%o11) matrix([0,x],[0,0],[0,0])
minor(A,i,j) que calcula el menor (i, j) de la matriz A (es decir elimina la fila i y
la columna j de A
(%o12) kill(all)$
(%i1) load("eigen")$
(%i2) A:matrix([2,0,1],[3,0,0],[5,1,1]);
(%o2) matrix([2,0,1],[3,0,0],[5,1,1])
(%i3) ss:ratsimp(gramschmidt(A));
(%o3) [[2,0,1],[3/5,0,-6/5],[0,1,0]]
Comprobemos que efectivamente los vectores son ortogonales para lo cual calculamos
el producto escalar entre ellos usando la orden innerproduct(u,v) donde u y v son los
correspondientes vectores:
Finalmente, si queremos construir los vectores unitarios, i.e., de norma 1, usamos el co-
mando unitvector(v) (para que funcione hay que cargar el paquete eigen)
(%i7) unitvector(ss[1]);unitvector(ss[2]);unitvector(ss[3]);
(%o7) [2/sqrt(5),0,1/sqrt(5)]
(%o8) [1/sqrt(5),0,-2/sqrt(5)]
(%o9) [0,1,0]
En este caso como la matriz es real también podríamos haber usado como producto escalar
las secuencias ss[1].ss[2]; ss[1].ss[3]; ss[2].ss[3]; lo que no es posible hacer en
el caso complejo. Como ejemplo compárese las salidas de ambas opciones para la matriz
i+2 0 1
3 0 0 .
5 1 − 2i 1
Para más detalle sobre como usar M AXIMA para resolver problemas de álgebra lineal
se recomienda consultar los apartados §23 (Matrices y Álgebra lineal), 65 (lapack) y 68
(linearalgebra) del manual de M AXIMA [1].
datos de crecimiento de la población mundial según datos de la Oficina del Censo de los
Estados Unidos que luego usaremos en algunos ejercicios. Para cargarlo lo primero que
hay que asegurarse es que M AXIMA reconoce dónde está para lo cual usamos el comando
file_search_maxima que ya comentamos en la página 13. A continuación cargamos el
paquete descriptive
A partir de este momento podemos trabajar con la variable mm como una matriz, por lo
que podemos usar cualquiera de los comandos válidos para el tratamiento de matrices.
Aquí nos interesará tener los vectores columna 1 y 2 de los datos.
(%i5) length(mm);length(xx);
(%o5) 31
(%o6) 31
(%i7) row(mm,31);row(xx,31);
(%o7) matrix([1980,4452557135,1.7,76294721])
(%o8) matrix([1980])
Podemos calcular la media y la varianza de los datos de una determinada columna con el
comando mean y var, respectivamente
Dichos comandos también funcionan cuando la entrada es una matriz, dando como resul-
tado el cómputo de la media o la varianza de cada una de las columnas. Por ejemplo
y que nos genera una lista con los valores de la expresión expr para cada k desde k0 inicial
hasta kfin final
y usamos cualquiera de los comandos para representar gráficas, como por ejemplo plot2d
(%i14) plot2d([discrete,lx,ly],[x,1945,1985],[logy],[style,points,lines],
[color, red ], [point_type, circle],[legend, "datos"],
[xlabel, "año"], [ylabel, "individuos"])$
(%t14) << Graphics >>
5e+09
datos
4.5e+09
4e+09
individuos
3.5e+09
3e+09
2.5e+09
2e+09
1945 1950 1955 1960 1965 1970 1975 1980 1985 1990
año
Figura 4.2: Datos de la población del censo de la Oficina del Censo de los Estados Unidos.
De la gráfica 4.2 parece razonable pensar que los datos se pueden aproximar median-
te una recta de regresión. Imaginemos que queremos aproximar los datos de la segunda
columna mediante la expresión y = ax + b, donde los valores de a y b los vamos a deter-
minar a partir de los propios datos de forma tal que la desviación media cuadrática sea
mínima, i.e., usando en método de los mínimos cuadrados. Para ello M AXIMA cuenta con
el paquete lsquares
Ante todo tenemos que generar una matriz de dos columnas, la primera serán las entradas
x y la segunda las y
(%i16) datos:submatrix(mm,3,4)$
length(datos);
(%o17) 31
(%i18) kill(a,b);
mse : lsquares_mse (datos, [x, y], y= a+b*x);
(%o18) done
(%o19) sum((datos[i,2]-b*datos[i,1]-a)^2,i,1,31)/31
Si queremos que M AXIMA intente resolver analíticamente el problema —lo cual no siem-
pre es capaz de hacer— hay que usar en vez de lsquares_estimates_approximate, el
comando lsquares_estimates, cuya sintaxis es
donde datos es una matriz de datos, lista de variables, es una lista con el nombre de
las variables correspondiente a cada columna de la matriz de datos, lista de parametros
es una lista con los parámetros del modelo y ecuacion es la ecuación que vamos usar para
el ajuste de datos.
Nótese que la salida son números racionales (y no en coma flotante), es decir la solución
es exacta. Finalmente dibujamos la gráfica de la función y = ax + b y la comparamos con
nuestros datos –ver gráfica de la izquierda en la figura 4.3—
82
5e+09 1e+10
datos datos
curva de ajuste curva de ajuste
4.5e+09
log(No. individuos)
4e+09
No. individuos
3.5e+09
3e+09
2.5e+09
2e+09 1e+09
1945 1950 1955 1960 1965 1970 1975 1980 1985 1945 1950 1955 1960 1965 1970 1975 1980 1985
(%i21) aa:rhs(sol[1][1]);bb:rhs(sol[1][2]);
(%o21) -1.2359822742463164*10^11
(%o22) 6.4636661890076451*10^7
(%i23) define(f(x), aa+bb*x);
(%o23) f(x):=6.4636661890076451*10^7*x-1.2359822742463164*10^11
(%i24) wxplot2d([[discrete,lx,ly],f(x)],[x,1945,1987],
[style,points,[lines,3]],[y,2*10^9,5*10^9],[ytics,5*10^8],
[color, red, blue],[point_type,bullet],
[legend,"datos", "curva de ajuste"],
[ylabel, "individuos"], [xlabel, ""])$
(%t24) << Graphics >>
(%i25) wxplot2d([[discrete,lx,ly],f(x)],[x,1945,1987],[color,red,blue],
style,points,[lines,3]],[point_type,bullet],
[legend,"datos","curva de ajuste"], [logy],
[ylabel, "individuos"], [xlabel, ""])$
(%t25) << Graphics >>
25
Parcial 1
Parcial 2
Final
20
2 4
15 6
3 5 8
7 9
1
10
0
10
Figura 4.4: Histograma con las notas del examen de la salida (o %29).
(%i26) l1:makelist(random(10),k,1,100)$
l2:makelist(random(10),k,1,100)$
l3: floor((l1+l2)/2)$
(%i29 barsplot( l1,l2,l3, box_width=1, fill_density = 1,
bars_colors=[blue,green,red],xlabel="",ylabel="",
sample_keys=["Parcial 1", "Parcial 2", "Final"])$
(%i30) n:makelist([suspenso,aprobado,notable,sobresaliente]
[random(4)+1], k,1,50)$
(%i31) piechart (n,title="Notas Mates Curso 1",dimensions=[1000,1000],
xtics=none,ytics=none,axis_top=false,axis_right=false,
axis_left=false,axis_bottom=false,yrange=[-1.4,1.4],
xrange = [-1.34, 1.34])$
Ahora generamos tres listas con las notas cualitativas del examen de una asignatura
durante tres cursos y las dibujamos (ver gráfica derecha de la figura 4.5):
(%i32) ne1:makelist([suspenso,aprobado,notable,sobresaliente][random(4)+1],
k,1,50)$
ne2:makelist([suspenso,aprobado,notable,sobresaliente][random(4)+1],
k,1,50)$
ne3:makelist([suspenso,aprobado,notable,sobresaliente][random(4)+1],
k,1,50)$
(%i35) barsplot(ne1,ne2,ne3,
title = "notas Mates",ylabel="Notas",groups_gap=4,fill_density=0.5,
bars_colors = [black,blue,red], ordering=ordergreatp,
84
notas Mates
20
Curso 1
Curso 2
Curso 3
Notas Mates Curso 1 sobresaliente
aprobado
notable 15
sobresaliente notable suspenso
suspenso
aprobado
Notas
10
dimensions=[1000,1200],yrange=[0,20],font="Arial", font_size=15,
sample_keys=["Curso 1","Curso 2","Curso 3"])$
continuous_freq(datos,No. de intervalos)
(%i36) mm3:makelist(random(11),k,1,100)$
Esta claro que un barsplot no es una buena opción en el caso de que queramos agru-
par más los datos, digamos en 5 clases. Para ello podemos usar la orden histogram que
construye el histograma con los datos distribuidos en el número de clases que fijemos
Como se ve de los gráficos generados por los comandos anteriores, incluso para represen-
tar los datos sin agrupar es mucho más conveniente, al menos visualmente, usar la orden
histogram en vez de barsplot.
Si queremos representar las notas del examen en un diagrama de pastel escribimos la
secuencia
R. Álvarez Nodarse Introducción a M AXIMA CAS 85
18 30
Nota del examen
16
4 25
14 3
20
12
5
10 15
1 7 8
8 0 2 10
10
6
6
4 9 5
2
0
0 0 2 4 6 8 10
Figura 4.6: Representación de las notas del examen usando barsplot y histogram, res-
pectivamente.
Un vistazo a la gráfica izquierda de la figura 4.7 nos indica claramente que es mejor dividir
los datos en clases más grandes. Agrupemos los datos en cinco clases
(%i41) clases:5$
contar: continuous_freq (mm3, clases);
pies:contar[2];
sum(pies[k],k,1,length(pies));
(%o42) [[0,2,4,6,8,10],[23,13,29,13,22]]
(%o43) [23,13,29,13,22]
(%o44) 100
La primera lista de la variable contar nos da las clases: la primera entrada contiene
los extremos de los subintervalos en que se han dividido los datos que en nuestro ca-
so son en [0,2] (ambos incluidos), el (2,4], (4,6], (6,8] y (8,10]. La segunda lista nos
dice cuantos datos hay en cada uno de los intervalos. Así en el primer intervalo (cla-
se) hay 23, en el segundo 13, etc. Lo que vamos a hacer para dibujar el diagrama de
pastel es construir una nueva lista que contenga los valores del 1 al 5 (nuestras clases)
repetidos tantas veces como aparecen el la lista pies (¿por qué?) para luego usar la or-
den continuous_freq (lista,[inic,fin,No. clases]) que genera dos listas, la prime-
ra contiene los intervalos definidos por No. clases comenzando por inic y terminando
por fin, y la segunda el número de elementos que contiene cada intervalo. Así tendremos
Figura 4.7: Representación de las notas del examen usando diagramas de pastel. A la
izquierda sin redefinir las clases y a la derecha después de agrupar los datos conveniente-
mente.
f (xi ) = yi , i = 1, 2, . . . , n. (4.4.1)
Existen varias formas de elegir la interpolante f (x). El modo más sencillo es suponer que
f (x) es un polinomio, en cuyo caso se puede comprobar que dados n + 1 puntos distintos
11
Como comentario extra hemos de destacar que en el momento de escribir estas notas ha sido imposible
exportar a pdf la salida de barplot.
12
En general este conjunto de valores pueden aparecer como resultado de un experimento o bien son
resultados de ciertos cálculos.
R. Álvarez Nodarse Introducción a M AXIMA CAS 87
siempre existe un único polinomio de interpolación de orden n que cumple con (4.4.1). En
este caso, el problema de interpolación se le denomina problema de interpolación polinó-
mica. Si suponemos que f (x) es una función racional entonces tendremos un problema de
interpolación racional; si f (x) está definida a trozos, un problema de Spline-interpolación
o interpolación por splines, etc. En este apartado discutiremos algunos de estos problemas.
Puesto que Pint (xi ) = yi (ver (4.4.1)), obtenemos un sistema de n ecuaciones con n
incógnitas (los coeficientes ck ) cuyo determinante siempre es diferente de cero (es un de-
terminante de Vandermonde cuyos coeficientes son todos distintos) y por tanto tiene una
única solución. Aunque formalmente podemos calcular el polinomio interpolador por el
método antes descrito, ellos es tremendamente ineficiente si el número de puntos a inter-
polar es alto (hay que invertir matrices grandes con pocos ceros). Una forma de evitar esto
es usar el método de interpolación de Lagrange que consiste en encontrar un polinomio,
que denotaremos por Lm (x), de orden a lo más m = n, que coincida en los puntos xi con
los valores yi , osea Lm (x) es tal que:
Para ello es suficiente utilizar el hecho de que lk (xi ) = δki , donde δki es el símbolo de Kro-
neker: δki = 1 si i = k y 0 si i 6= k. Es sencillo comprobar que el polinomio de interpolación
de Lagrange (4.4.3) cumple con las condiciones (4.4.2) y por tanto es realmente una de
las soluciones del problema de interpolación planteado. Además, por la unicidad del pro-
blema de interpolación polinómica, toda solución polinómica del mismo coincide con él.
Numéricamente el polinomio de interpolación se puede calcular mediante la fórmula de
Newton. Describiremos brevemente este algoritmo.
Busquemos el polinomio de interpolación de la siguiente forma:
y1 = a0
y2 = a0 + a1 (x2 − x1 )
.. ..
. .
yn+1 = a0 + a1 (xn+1 − x1 ) + a2 (xn+1 − x1 )(xn+1 − x2 )+
+ · · · + an (xn+1 − x1 )(x − x2 ) . . . (xn+1 − xn ).
88
De la fórmula anterior se sigue que al agregar un nuevo punto de interpolación (xn+2 , yn+2 )
el polinomio de interpolación cumple con la propiedad:
A estos coeficientes ak se les llama diferencias divididas de orden k y se les denota por: ak =
[y1 , y2 , ..., yk+1 ]. Comparando la fórmula (4.4.4) con (4.4.3) concluimos que el coeficiente
cn de la potencia xn coincide con an , por tanto
n+1
X yk
an = [y1 , y2 , ..., yn+1 ] = n+1
.
k=1
Y
(xk − xi )
i=1
i 6= k
Si los números yk son los valores de cierta función f (x) en los puntos xk entonces
(4.4.4) se puede escribir de la forma:
n+1
X
Pn (f, x) = [f (x1 ), f (x2 ), ..., f (xk+1 )](x − x1 )(x − x2 ) . . . (x − xk ).
k=1
(%i52) kill(all)$
(%i1) load(interpol)$ load(draw)$
(%i3) datos:[[1,2],[3/2,1],[2,0],[5/2,-1],[3,1/2],[4,1]]; length(datos);
(%o3) [[1,2],[3/2,1],[2,0],[5/2,-1],[3,1/2],[4,1]]
(%o4) 6
(%i7) lagrange(datos)$ /* Polinomio de Lagrange */
ratsimp(%)$ define(lag(x),%);
(%o7) lag(x):=-(52*x^5-580*x^4+2435*x^3-4835*x^2+4620*x-1764)/36
(%i8) define(f(x),x+sin(x));
kill(x)$ a:0$ b:%pi$ Nu:10$ h:(b-a)/(Nu)$
x[0]:a$ x[n]:=x[0]+n*h;
pp10:makelist( float([x[k],f(x[k])]),k,0,Nu)$
(%o9) f(x):=sin(x)+x
(%o16) x[n]:=x[0]+n*h
y la dibujamos
(%i17) define(lag10(x),lagrange(pp10))$
(%i18) wxdraw2d(color=red, key="polinomio de Lagrange",line_width=3,
explicit(lag10(x),x,0,%pi),yrange=[-.2,4.3],
point_type = filled_diamant, point_size = 3,
color = blue, key = "Puntos", points(pp10))$
(%t18) (Graphics)
4
polinomio de Lagrange polinomio de Lagrange
8
3.5 x+sen(x) x+sen(x)
Puntos Puntos
3 6
2.5
4
2
2
Y
1.5
0
1
0.5 -2
0
-4
-0.5
0 0.5 1 1.5 2 2.5 3 -4 -2 0 2 4 6
X X
Como ejercicio comprobar que ocurre si aumentamos el número de puntos (por ejem-
plo tomando Nu=20 o Nu=40).
Consideremos ahora la función de Runge f (x) = 1/(1 + a2 x2 ) y estudiemos la interpo-
lación de Lagrange. Comenzaremos con 10 puntos:
(%t19) kill(all)$
(%i1) load(interpol)$ load(draw)$
(%i3) kill(x,pp,Nu,h)$ /* Chebyshev */
define(f(x),1/(1+25*x^2));
a:-1$ b:1 $Nu:20$ h:(b-a)/(Nu)$
x[0]:a$ x[n]:=x[0]+n*h;
pp10:makelist(float([x[k],f(x[k])]),k,0,Nu)$
(%o4) f(x):=1/(25*x^2+1)
(%o10) x[n]:=x[0]+n*h
90
(%i12) ratprint:false$
define(lag10(x),ratsimp(lagrange(pp10)))$
(%i14) wxdraw2d(color=red, key="polinomio de Lagrange",line_width=1,
explicit(lag10(x),x,-1,1), key="1/(1+25 x2 )",yrange=[-2,5.5],
color= black,explicit(f(x),x,-1,1),point_type=filled_diamant,
point_size=1, color=blue, key = "Puntos", points(pp10))$
(%t14) (Graphics)
A la hora de simplificar con ratsimp M AXIMA primero transforma todos los números en
coma flotante por sus correspondientes fracciones y en cada caso genera un comentario
del tipo:
Esto se debe a que la variable ratprint está definida por defecto como true, por lo que la
hemos redefinido para que tome el valor false y así eliminar dichos comentarios. Como
se ve en la figura 4.9 hay una enorme oscilación cerca de los extremos.
3 3
2 2
Y
1 1
0 0
-1 -1
-2 -2
-1 -0.5 0 0.5 1 -1 -0.5 0 0.5 1
X X
Esto empeora, como se ver el la gráfica derecha de la figura figura 4.9, si aumentamos
el número de puntos de interpolación. Por ejemplo tomemos 20 puntos:
(%i24) ratprint:false$
define(lag20(x),ratsimp(lagrange(pp20)))$
(%i26) wxdraw2d(color=red, key="polinomio de Lagrange",line_width=1,
explicit(lag20(x),x,-1,1),key="1/(1+25 x2 )",yrange=[-2,5.5],
color= black,explicit(f(x),x,-1,1),point_type=filled_diamant,
point_size = 1, color = blue, key = "Puntos", points(pp20))$
(%t26) (Graphics)
Para mejorar este resultado podemos usar en vez de nodos equidistantes los nodos de
Chebyshev definidos en un intervalo [a, b] mediante la expresión:
a+b a−b h πi
x(k) = + cos (2k − 1) ,
2 2 2n
(%i33) ratprint:false$
define(lag10c(x),ratsimp(lagrange(pp10c)))$
(%i34) wxdraw2d(color=red, key="polinomio de Lagrange",line_width=1,
explicit(lag10c(x),x,-1,1), key="1/(1+25 x2 )", yrange=[-.2,1.2],
color= black,explicit(f(x),x,-1,1), point_type = filled_diamant,
point_size = 1, color = blue, key = "Puntos", points(pp10c))$
(%t34) (Graphics)
La gráfica la podemos ver en la figura 4.10 (izquierda). A diferencia del caso con nodos
equidistantes, la aproximación mejora notablemente si aumentamos en número de puntos
tal y como se ve en la figura 4.10 (derecha):
1.2 1.2
polinomio de Lagrange polinomio de Lagrange
1/(1+25 x2) 1/(1+25 x2)
1 Puntos 1 Puntos
0.8 0.8
0.6 0.6
Y
Y
0.4 0.4
0.2 0.2
0 0
-0.2 -0.2
-1 -0.5 0 0.5 1 -1 -0.5 0 0.5 1
X X
4.4.3. Splines.
Hay otra forma mucho mejor de interpolar que la polinómica consistente en usar cier-
tas funciones a trozos. Esta forma de interpolar se conoce como interpolación por splines.
Vamos a comentar brevemente la forma más común: los splines cúbicos que denotaremos
por S(x). La idea es la siguiente. Imaginemos que tenemos en el intervalo [a, b] los no-
dos de interpolación a = x0 , x1 , · · · , xn−1 , xn = b a los que le corresponden las imágenes
yk = f (xk ). La función S(x) va a ser una función definida a trozos en el intervalo [a, b]
definida en cada subintervalo [xk , xk+1 ], k = 0, . . . , n − 1, mediante un polinomio de grado
3, Sk (x), k = 0, . . . , n − 1 tal que Sk (xk ) = yk , k = 0, . . . , n − 1. Vamos ahora a imponer
que S(x) sea continua en [a, b]. Ello implica que los polinomios Sk−1 (x) y Sk (x) deben
tomar el mismo valor en los puntos tk+1 , i.e.,
Lo mismo haremos con la primera y segunda derivada de S(x) en [a, b] es decir, se tiene
cspline(datos) o cspline(datos,d1=val1,dn=val2))
donde los datos han de ser una lista del tipo [[x1 , y1 ], . . . , [xn , yn ] o [y1 , . . . , yn ], en cuyo caso
se asume que x1 = 1, . . . xn = n. Los valores val1 y val2 son los valores de la primera
R. Álvarez Nodarse Introducción a M AXIMA CAS 93
derivada en los puntos extremos x1 y xn que por defecto toman los valores 'unknown
(indeterminados).
Veamos un par de ejemplos. Comencemos nuevamente con los datos que usamos en la
interpolación de Lagrange con un spline natural:
(%i41) datos:[[1,2],[3/2,1],[2,0],[5/2,-1],[3,1/2],[4,1]];
(%o41) [[1,2],[3/2,1],[2,0],[5/2,-1],[3,1/2],[4,1]]
(%i45) cspline(datos)$ /* Splin cúbico natural */
ratsimp(%)$
define(fs(x),%)$
wxdraw2d(color=red, key="spline cúbico natural",line_width=2,
explicit(fs(x),x,0.5,5), point_type=plus, point_size=4,
color = blue, key = "Puntos", points(datos))$
(%t45) (Graphics)
(%i46) cspline(datos,d1=0,dn=0)$
ratsimp(%)$
define(fs1(x),%)$
wxdraw2d(color=red, key="spline cúbico",line_width=2,
explicit(fs1(x),x,0.5,5), point_type=plus, point_size=4,
color = blue, key = "Puntos", points(datos))$
(%t49) (Graphics)
3 3
spline cúbico natural spline cúbico
2.5 Puntos 2.5 Puntos
2 2
1.5 1.5
1 1
Y
0.5 0.5
0 0
-0.5 -0.5
-1 -1
0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
X X
Figura 4.11: Spine cúbico natural obtenido a partir de la lista data (izquierda) y fijando los
valores de la derivada en los extremos iguales a cero (derecha). Nótese que en el segundo
caso S(x) tiene extremos locales en los puntos x = 1 y x = 4.
(%i50) kill(f,chex,Nu,ppc)$
define(f(x),1/(1+25*x^2));
Nu:20$
chex[k]:=(a+b)/2+((a-b)/2)*cos((2*k-1)*%pi/(2*Nu))$
94
ppc:makelist(float([chex[k],f(chex[k])]),k,1,Nu)$
(%o51) f(x):=1/(25*x^2+1)
(%i55) define(srun(x),cspline(ppc))$
wxdraw2d(color=red, key="spline cúbico",line_width=2,
explicit(srun(x),x,-1,1), key="1/(1+25 x2 )", yrange=[-.2,1.2],
color= black,explicit(f(x),x,-1,1), point_type=filled_diamant,
point_size = 1, color = blue, key = "Puntos", points(ppc))$
(%t56) (Graphics)
1.2 1.2
spline cúbico spline cúbico
1/(1+25 x2) 1/(1+25 x2)
1 Puntos 1 Chebyshev
0.8 0.8
0.6 0.6
Y
Y
0.4 0.4
0.2 0.2
0 0
-0.2 -0.2
-1 -0.5 0 0.5 1 -1 -0.5 0 0.5 1
X X
Figura 4.12: Spline cúbico natural para la función de Runge f (x) = 1/(1 + 25x2 ) en 20
puntos definidos a partir de 20 nodos de Chebyshev en [−1, 1] (izquierda) y la compara-
ción entre ambas aproximaciones —polinómica y splines— (derecha).
Nótese que aunque en la gráfica de la derecha de la figura 4.12 las curvas del spline y
la del polinomio interpolador son casi idénticas, el spline es mucho más útil ya que no
tenemos el problema de las inestabilidades si el número de nodos es muy grande (en cuyo
caso el grado del polinomio interpolador también es muy elevado). Esto es especialmente
visible si aumentamos el número de puntos de interpolación de la función, por ejemplo a
50. Elegiremos además una función muy sencilla, la función sin(x) en el intervalo [0, 1]:
Evaluemos ahora el polinomio interpolador en los puntos de los nodos de forma exacta
(trabajando simbólicamente):
(%i68) makelist(lagsin(float(x[4*k])),k,0,Nu/4);
(%o68) [0.0,0.07991469396918213,0.1593182072747862,0.2377048479005349,...,
5.479044778849127*10^7,3.05675556109827*10^8,7.931400833012784*10^9]
Nótese como los últimos valores comienzan a ser cada vez mayores. En cambio, con los
splines no ocurre lo mismo:
(%o69) kill(all)$
(%i1) load(interpol)$
(%i2) kill(x,pp,Nu,h,splsin)$
define(f(x),sin(x));
a:0$ b:1 $Nu:50$ h:(b-a)/(Nu)$
x[0]:a$ x[n]:=x[0]+n*h;
pp:makelist([x[k],f(x[k])],k,0,Nu)$
define(splsin(x),ratsimp(cspline(pp)))$
(%o3) f(x):=sin(x)
(%o9) x[n]:=x[0]+n*h
Como ejercicio proponemos al lector que encuentre el spline para la función de Runge
en 20 puntos equidistantes y compare los resultados con los aquí discutidos.
Finalmente debemos mencionar que el paquete interpol cuenta también con el co-
mando ratinterpol que genera una función racional interpoladora con el grado del nu-
merador fijado por el usuario.
Veamos un ejemplo muy sencillo:
(%i1) kill(all)$
load(interpol)$
(%i2) datos:[[1,2],[3/2,1],[2,0],[5/2,-1],[3,1/2],[4,1]];
ratinterpol(datos,2)$ /* Funcion racional */
ratsimp(%)$
define(fr(x),%);
(%o2) [[1,2],[3/2,1],[2,0],[5/2,-1],[3,1/2],[4,1]]
(%o5) fr(x):=(39*x^2-189*x+222)/(10*x^3-50*x^2+58*x+18)
(%i6) wxdraw2d(color=red, key="Interpolacion racional",line_width=3,
explicit(fr(x),x,0.5,4.5), point_type = filled_diamant,
point_size=2, color=blue, key ="Puntos", points(datos))$
explicit(cspline(datos),x,0.5,4.5),
color=blue, key="Función racional",line_width=3,
explicit(fr(x),x,0.5,4.5),
point_type = plus, point_size=3, color=black, key="Puntos",
points(datos),yrange = [-2,5])$
Y
2
1
1
0.5
0
0
-0.5 -1
-1 -2
0.5 1 1.5 2 2.5 3 3.5 4 4.5 0.5 1 1.5 2 2.5 3 3.5 4 4.5
X X
Figura 4.13: Interpolación racional de los datos [1, 2], [3/2, 1], [2, 0], [5/2, −1], [3, 1/2], [4, 1]
usando el comando ratinterpol (izquierda) y comparación con la interpolación por spli-
nes y el polinomio de Lagrange (derecha).
Para más detalle sobre este comando recomendamos al lector que consulte el ma-
nual [1].
Para terminar este capítulo vamos a discutir brevemente una función muy especial: la
función anónima lambda. Este es un concepto muy usado en programación que consiste
en crear funciones que no tienen un nombre especificado. Por ejemplo, en M AXIMA ya he-
mos visto un sinnúmero de funciones matemáticas teniendo cada una de ellas un nombre
determinado. Hay ciertas situaciones donde es conveniente definir una función pero sin
asignarle un nombre específico. Es ahí donde juegan un papel importante estas funciones.
Más adelante usaremos una en la resolución de un problema muy concreto por lo que en
este apartado vamos a discutir brevemente su uso.
Su sintaxis más usual es
donde la lista [x_1, ..., x_m] son sus argumentos y expr_1, ..., expr_n) es cierta
secuencia de órdenes o expresiones. Veamos unos ejemplos sencillos. Por ejemplo, defina-
mos por un lado la función f (x) = xa de una variable x con a fijo, y por otro la función de
dos variables g(x, a) = xa :
(%i1) f:lambda([x],x^a);
(%o1) lambda([x],x^a)
R. Álvarez Nodarse Introducción a M AXIMA CAS 97
(%i2) f(x);
(%o2) x^a
(%i3) f(2);
(%o3) 2^a
(%i4) g: lambda([x,a],x^a);
(%o4) lambda([x,a],x^a)
(%i5) g(x,a);
(%o5) x^a
(%i6) g(x,a);
(%o6) x^a
(%i7) g(2,3);
(%o7) 8
(%i8) f(t);
(%o8) t^a
El valor que devuelve la función es la salida de la última orden expr_n, es decir fijados los
argumentos o variables (locales) las órdenes expr_1, ..., expr_n se ejecutan secuen-
cialmente:
(%i9) h: lambda([x,a,b],y:x^b,a*y);
(%o9) lambda([x,a,b],y:x^b,a*y)
(%110) h(x,a,b);
(%o10) a*x^b
¿Qué ocurre cuando una de las variables toma cierto valor global?
(%i11) x:2;
(%o11) 2
(%i12) f(x);
(%o12) 2^a
(%i13) g(3,a);
(%o13) 3^a
(%i14) g(x,a);
(%o14) 2^a
(%i15) g(t,a);
(%o15) t^a
En muchas ocasiones lambda viene acompañado del operador apply cuya sintaxis es
y que lo que hace es evaluar el nombre de la función F en sus argumentos. Por ejemplo, si
tenemos una función propia de M AXIMA (el seno en nuesto ejemplo) podemos aplicarla a
una lista directamente
(%i16) l:[a,b,c];
(%o16) [a,b,c]
(%i17) sin(l);
(%o17) [sin(a),sin(b),sin(c)]
(%i19) apply(sin,[l]);
(%o19) [sin(a),sin(b),sin(c)]
En este caso la razón se debe a que demoivre tiene dos posibles usos: uno como función
(para escribir en forma trigonométrica los números complejos) y la otra como una variable
global de M AXIMA. Si queremos evitar la evaluación usamos la comilla simple '
Volvamos a la función lambda y veamos que efectivamente es anónima. Para ello use-
mos la función anónima f definida en la entrada (%i1) y preguntemos a M AXIMA por su
definición (lo que se hace usando el comando dispfun)
Como vemos M AXIMA no reconoce que hayamos definido ninguna función f , a diferencia
del caso cuando usamos la definición directa:
(%i26) ff(x):=z^a;
(%o26) ff(x):=z^a
(%i27) dispfun(ff);
(%t27) ff(x):=z^a
(%o27) [%t27]
(%i28) apply (dispfun, [ff]);
(%t28) ff(x):=z^a
(%o28) [%t28]
(%i29) functions;
(%o29) [ff(x)]
Conviene hacer notar la existencia de otro comando muy útil cuando se quiere aplicar una
misma función a varios elementos de una lista de forma independiente. Ya nos encontra-
mos con él en la página 51 al dibujar la región definida entre dos funciones. Su sintaxis
es
R. Álvarez Nodarse Introducción a M AXIMA CAS 99
Escencialmente lo que hace map es aplicar f a cada una de las subpartes de las expresiones,
donde f puede ser tanto el nombre de una función de n argumentos como una expresión
lambda de n argumentos.
Este procedimiento es muy útil en el caso cuando la expresión sobre la que se va a
actuar es muy extensa y el uso directo sobre ella pudiese agotar el espacio de almacena-
miento durante el transcurso del cálculo. Así, en el primer caso aplicamos la función gg a
cada sumando de la expresión de la derecha (si queremos aplicarla sobre la suma se ha
de proceder de forma distinta), en el segundo están involucradas dos expresiones (en este
caso listas), y finalmente lo usamos en conjunción con una función lambda
(%i1) map(gg,x+a*y+b*z);
(%o1) gg(b*z)+gg(a*y)+gg(x)
(%i2) map(gg,x+a*y+b*z);
(%o2) gg(b*z)+gg(a*y)+gg(x)
(%i3) map(gg,[x+a*y+b*z]);
(%o3) [gg(b*z+a*y+x)]
(%i4) map("^",[a,b,c],[1,2,3]);
(%o4) [a,b^2,c^3]
(%i5) map ( lambda ([x], sin(x)*x^2), [a, b, c, d, e]);
(%o5) [a^2*sin(a),b^2*sin(b),c^2*sin(c),d^2*sin(d),e^2*sin(e)]
Por último vamos a mostrar que en efecto map actúa por separado en cada una de las
subpartes de las expresiones de la derecha. Para ello mostraremos las diferentes salidas a
la hora de simplicar una expresión algebraica con el comando ratsimp:
(%i5) ratsimp(x/(x^2+x)+(y^2+y)/y);
(%o5) ((x+1)*y+x+2)/(x+1)
(%i6) map(ratsimp, x/(x^2+x)+(y^2+y)/y);
(%o6) y+1/(x+1)+1
(%i7) map(ratsimp, [x/(x^2+x),(y^2+y)/y]);
(%o7) [1/(x+1),y+1]
Conviene destacar que esta función tiene muchas cosas en común con maplist cuando se
aplica a listas. Para más detalles remitimos al lector al manual de M AXIMA [1].
100
Capítulo 5
desolve([eq1,eq2,...,eqn],[y1,y2,...,yn])
donde eq1,..., eqn denota las ecuaciones diferenciales (lineales) e y1,...,yn las fun-
ciones desconocidas. Para definir la ecuación debemos usar la sintaxis correcta que consis-
te en escribir las funciones con sus variables pues en otro caso obtendremos errores. Por
ejemplo, la ecuación y 0 = y la tenemos que escribir de la siguiente forma:
(%i2) desolve(edo,y(x));
(%o2) y(x)=y(0)*%e^x
(%i3) atvalue(y(x),x=0,1);
desolve(edo,y(x));
(%o3) 1
(%o4) y(x)=%e^x
Es importante saber que para que la orden desolve funcione correctamente hay que es-
pecificar para las funciones desconocidas sus correspondientes variables, pues en caso
contrario M AXIMA nos da un error:
101
102
(%i5) kill(y)$
edo1:diff(y,x,1) = y;
desolve(edo,y);
(%o6) 0=y
length: argument cannot be a symbol; found y
-- an error. To debug this try: debugmode(true)
En este caso lo que ocurre es que M AXIMA asume que y es una constante y por tanto y 0 = 0.
Podríamos pensar que si le decimos a M AXIMA que y depende de x, para lo que podemos
usar el comando depends que ya vimos antes en la página 36
depends(y,[x]); diff(y,x,1) = y;
(%i8) kill(y)$
edo2:diff(y(x),x,1) = -1/2*y(x)+sin(x);
desolve(edo2,y(x))$
expand(%);
(%o9) 'diff(y(x),x,1)=sin(x)-y(x)/2
(%o11) y(x)=(2*sin(x))/5-(4*cos(x))/5+y(0)*%e^(-x/2)+(4*%e^(-x/2))/5
(%i12) atvalue(y(x),x=0,1);
desolve(edo2,y(x));
(%o12) 1
(%o13) y(x)=(2*sin(x))/5-(4*cos(x))/5+(9*%e^(-x/2))/5
Para definir la función solución y luego trabajar con ella usamos, como ya hemos visto, la
orden define
(%i14) define(soledo2(x),second(%));
(%o14) soledo2(x):=(2*sin(x))/5-(4*cos(x))/5+(9*%e^(-x/2))/5
Además hemos usado un comando muy útil second que, dada una ecuación
(%i15) wxplot2d(soledo2(x),[x,0,18],[ylabel,"y"])$
(%t15) << Graphics >>
R. Álvarez Nodarse Introducción a M AXIMA CAS 103
1.5 4.5
1 4
3.5
0.5
3
y
y
0
2.5
-0.5 2
-1 1.5
0 2 4 6 8 10 12 14 16 18 1 1.5 2 2.5 3 3.5 4 4.5 5
x x
donde ilt significa trasformada inversa de Laplace (en sus siglas inglesas inverse Lapla-
ce transform), pero no nos permite obtener ningún valor de la misma. En este caso es
conveniente utilizar otro comando: el comando ode2 cuya sintaxis es
y que resuelve EDOs de primer y segundo orden intentando reconocer alguna de las ecua-
ciones tipo más usuales: lineales, separables, de Bernoulli, etc. o reducibles a ellas.
Por ejemplo, resolvamos la EDO z 0 = −z + x:
(%i18) 'diff(z,x)=x-z;
ode2('diff(z,x)=x-z,z,x)$
expand(%);
(%o18) 'diff(z,x,1)=x-z
(%o20) z=%c*%e^(-x)+x-1
Si queremos resolver el PVI z 0 = −z + x, z(1) = 2 hay que usar el comando ic1 cuya
sintaxis es
(del inglés “right hand side”, miembro derecho) y lhs (“left hand side”) miembro izquierdo, respectivamente.
104
(%i21) expand(ic1(%,x=1,z=2));
(%o21) z=2*%e^(1-x)+x-1
(%i22) define(s1(x),second(%));
(%o22) s1(x):=2*%e^(1-x)+x-1
que podemos representar en una gráfica (ver figura 5.1, gráfica de la derecha)
(%i23) wxplot2d(s1(x),[x,1,5],[ylabel,"y"])$
(%t23) << Graphics >>
Nótese que en la entrada ( %i18) hemos escrito 'diff y no diff. La razón es que el
apóstrofe ' delante del comando diff obliga a M AXIMA a no ejecutar la orden (probar
sin el apóstrofe)2 . Otra posibilidad es decirle a M AXIMA que z depende de x, lo que pode-
mos hacer, como hemos visto anteriormente, usando el comando depends. Como ejercicio
recomendamos comprobar que ocurre si usamos la secuencia
depends(z,x);
ode2(diff(z,x)=x-z,z,x);
expand(ic1(%,x=1,z=2));
(%i23) kill(w)$
'diff(w,x)=1+w^2;
ode2('diff(w,x)=1+w^2,w,x)$
sol:expand(%);
expand(ic1(sol,x=0,w=0));
(%o24) 'diff(w,x,1)=w^2+1
(%o26) atan(w)=x+%c
(%o27) atan(w)=x
(%i28) sol:solve(%,w);
(%o28) [w=tan(x)]
La última salida (entre “[ ]”) es una lista. Las listas son especialmente importantes en
M AXIMA como ya hemos comentado en el apartado 2.1 (ver página 14). En este caso sim-
plemente nos interesa extraer un elemento dado de la lista lo que se hace, como ya vimos,
usando el comando part(lista,no del elemento) (o bien, en nuestro caso escribiendo
sol[1]) así que hacemos
(%i29) part(%,1);
(%o29) w=tan(x)
(%i30) define(solw(x),second(%));
(%o30) solw(x):=tan(x)
2
Véase el apartado §8.1 del manual [1] para más detalles.
R. Álvarez Nodarse Introducción a M AXIMA CAS 105
Ecuación separable:
3 d
x (y − 1) y + (x − 1) y 3 = 0.
dx
Ecuación homogénea:
2 d
3xy y + y 3 + x3 = 0.
dx
Reducible a homogénea:
d y+x−1
y= .
dx −y + x − 1
Ecuación exacta:
3 d
y + 8y + 4x3 = 0.
8x − 4y
dx
Ecuación de Bernoulli:
d √
y − y + y = 0.
dx
(%i31) ode2('diff(z,x)=x-sin(z),z,x);
(%o31) false
La razón es que M AXIMA no reconoce ningún patrón en esta ecuación. Cuando esto ocurre
no queda más remedio que usar algún método numérico. Más adelante explicaremos el
funcionamiento de un par de métodos muy sencillos, mientras que aquí nos restringiremos
a mostrar como se pueden resolver numéricamente las EDOs usando M AXIMA.
Comenzaremos usando el comando runge1 que permite resolver numéricamente PVI
de primer orden del tipo y 0 = f (x, y), y(x0 ) = y0 con M AXIMA usando en método de
Runge-Kutta. Para ello lo primero que tenemos que hacer es cargar el paquete numérico
diffeq y luego ejecutar dicho comando. La sintaxis de runge1 es la siguiente:
(%i32) kill(all);
(%o0) done
(%i1) load(diffeq);
(%o1) /usr/share/maxima/5.20.1/share/numeric/diffeq.mac
Como esta ecuación es exactamente resoluble podemos comparar sus gráficas. Para ello
primero usamos ode2 e ice1 para resolver analíticamente el PVI:
(%i6) ode2('diff(w,x)=1+w,w,x)$
sol:expand(%);
expand(ic1(sol,x=0,w=1));
define(solw(x),second(%));
(%o7) w=%c*%e^x-1
(%o8) w=2*%e^x-1
(%o9) solw(x):=2*%e^x-1
(%i10) wxplot2d([[discrete,solnum[1],solnum[2]],solw(x)],[x,0,1],
[y,1,5],[legend,"sol. numerica","solucion exacta"],
[xlabel,"x"],[ylabel,"y"],[color,red,blue],[point_type,plus],
[style,[points,5],[lines,2]])$
(%t10) << Graphics >>
(%i11) g(x,y):=x-sin(y);
sol2:runge1(g,0,1,1/20,1);
(%o11) g(x,y):=x-sin(y)
(%o12) [[0.0,0.05,..., 0.9,0.95],
[1.0,0.95944094204897, ... ,0.75740012409521,0.7689229050892],
[-0.8414709848079,-0.76887080939197, ... ,0.25463842295662]]
(%i13) wxplot2d([discrete,sol2[1],sol2[2]],[x,0,1.01],
[point_type,diamond],[legend, "y(x) con runge1"],
[xlabel, "x"], [ylabel, "y"], [color,red],
[style,[points,3]])$
(%t13) << Graphics >>
R. Álvarez Nodarse Introducción a M AXIMA CAS 107
5 1
sol. numerica y(x) con runge1
4.5 solucion exacta
0.95
4
0.9
3.5
3 0.85
y
y
2.5
0.8
2
0.75
1.5
1 0.7
0 0.2 0.4 0.6 0.8 1 0 0.2 0.4 0.6 0.8 1
x x
rk(f,y,y0,[x,x0,x1,h])
(%i14) load(dynamics)$
(%i15) h:1/20; kill(x,y)$
numsolrk:rk(x-sin(y),y,1,[x,0,1,h])$
(%o15) 1/20
(%i17) numsolrk;
(%o18) [[0,1],[0.05,0.95973997169251],[0.1,0.92308155305544], ...
[0.95,0.77210758398484],[1.0,0.78573816934072]]
La salida de rk es justo una lista que entiende perfectamente el comando plot2d por lo
que podemos dibujar la solución y comparar ambas salidas numéricas.
1 1
y(x) con rk runge1
rk
0.95 0.95
0.9 0.9
0.85 0.85
y
y
0.8 0.8
0.75 0.75
0.7 0.7
0 0.2 0.4 0.6 0.8 1 0 0.2 0.4 0.6 0.8 1
x x
Para terminar este apartado mostraremos como se pueden exportar a un fichero los re-
sultados de una simulación realizada con M AXIMA. Para ello usaremos la orden
write_data(salida,fichero). Como ejemplo exportaremos la salida del comando rk que
ya hemos visto antes (ver página 5.2) y que genera una lista de datos. Concretamente re-
solveremos la ecuación
con x(0) = y(0) = 0. Así, cargamos el paquete y definimos la función y los parámetros del
problema:
(%i1) load("dynamics")$
kill(w,f,x,y,t)$
w:float(sqrt(2)/10);tau:100/w;
define(f(t),(cos(w*t)+cos(2*w*t))*(1-exp(t/tau)));
(%o3) 0.1414213562373095
(%o4) 707.1067811865476
(%o5) f(t):=(cos(0.282842712474619*t)+cos(0.1414213562373095*t))*
(1-%e^(0.001414213562373095*t))
Como comentario adicional queremos mencionar que hay una orden que nos permite
conocer el tiempo que tarda M AXIMA en realizar las operaciones. Ello es interesante cuan-
do tenemos un programa que requiere muchas operaciones y queremos estimar el tiempo,
o bien si lo estamos ejecutando en segundo plano tal y como explicaremos a continuación.
El comando en cuestión es time. Si en nuestro ejemplo queremos saber cuanto demora la
resolución de la ecuación (véase la salida %o6) escribimos
(%i8) time(%o6);
(%o8) [0.11]
que indica que ha tardado 0.11 segundos. También podemos escribir una serie de salidas
(%i9) time(%o6,%o7);
(%o9) [0.11,0.03]
y time nos devuelve una lista con los tiempos que usa M AXIMA para tratar cada una de
ellas. También hay una variable que controla de forma global la impresión de los tiempos:
showtime. De hecho si hacemos showtime:true M AXIMA devuelve el tiempo de ejecución
de cada una de las líneas de salida.
Para recuperar los datos usamos las órdenes read_matrix y file_search que ya vimos
en la página 79
(%i10) kill(all)$
(%i1) mm:read_matrix (file_search ("/home/renato/solnum.dat"))$
(%i2) xx1:makelist(col(mm,1)[k][1],k,1,length(mm))$
yy1:makelist(float(col(mm,2)[k][1]),k,1,length(mm))$
yyp:makelist(float(col(mm,3)[k][1]),k,1,length(mm))$
(%i5) wxplot2d([discrete,xx1,yy1],[xlabel,"t"],[ylabel,"x(t)"]);
(%i6) wxplot2d([discrete,xx1,yyp],[xlabel,"t"],[ylabel,"x'(t)"]);
80 3
70 2.5
60 2
1.5
50
1
40
x'(t)
x(t)
0.5
30
0
20
-0.5
10 -1
0 -1.5
-10 -2
0 20 40 60 80 100 0 20 40 60 80 100
t t
Figura 5.4: A la izquierda vemos la solución numérica del PVI (5.2.1) usando el comando
rk mientras que a la derecha están representados los valores de la primera derivada en
función de t.
Como ya hemos visto son pocas las EDOs que se pueden resolver analíticamente, es
por ello que se necesita de métodos fiables para obtener la solución de una EDO numéri-
camente. Aunque M AXIMA cuenta con las órdenes runge1 y rk comentadas en el apartado
anterior vamos a mostrar aquí como implementar un método numérico con M AXIMA. Por
simplicidad implementaremos el método de Euler y una de sus variantes más sencillas.
Supongamos que queremos resolver el problema de valores iniciales
d y(x)
= f (x, y), y(x0 ) = y0 . (5.3.1)
dx
Es obvio que usando un ordenador sólo podremos resolver el problema de valores ini-
ciales en un intervalo acotado, digamos [x0 , x0 + l] (aunque l podría ser muy grande). Para
ello vamos a dividir el intervalo en N subintervalos [x0 , x1 ]∪[x1 , x2 ]∪· · ·∪[xN −1 , xN ], xN =
x0 + l. Supongamos que hemos encontrado los valores de y en los puntos x0 , x1 , . . . , xN ,
que denotaremos por y0 , y1 , . . . , yN . Entonces, para encontrar una solución aproximada
yb(x) podemos unir los puntos (xi , yi ), i = 0, 1, . . . , N mediante líneas rectas (ver figura
5.5). Es evidente que si el valor yi es bastante cercano al valor real y(xi ) para todos los
i = 0, 1, . . . , N , entonces, al ser yb e y funciones continuas, la solución aproximada yb(x)
estará “muy cercana” a la solución real y(x) en cada uno de los intervalos [xi , xi+1 ].
Vamos a usar por simplicidad intervalos iguales, es decir, vamos a escoger los nodos
xi equidistantes. Lo anterior se conoce en la teoría de métodos numéricos como una red
equiespaciada o uniforme de paso h = l/N . Así pues tendremos las siguientes ecuaciones:
xk = x0 + kh = x0 + k Nl , k = 0, 1, . . . , N , xk+1 = xk + h. Además, está claro que la única
información que tenemos para calcular los valores yi , aparte de la condición inicial, es la
propia EDO que satisface nuestra incógnita y(x). ¿Cómo encontrar entonces los valores
yi ? La idea es como sigue:
^
y y(x)
y(x)
x0 x1 x2 xk
El método de Euler.
y 00 (xk ) 2
y(xk+1 ) = y(xk + h) = y(xk ) + y 0 (xk )h + h + ··· . (5.3.2)
2!
Como y 0 (xk ) = f (xk , y(xk )), entonces
d d y d ∂f (x, y) ∂f (x, y) ∂y
y 00 (xk ) = = (f (x, y(x))) = +
dx dx dx ∂x ∂y ∂x
x=xk x=xk (x,y)=(xk ,y(xk )
∂f (x, y) ∂f (x, y)
= + f (x, y) .
∂x ∂y
(x,y)=(xk ,y(xk )
La aproximación más sencilla es por tanto cuando nos quedamos en la serie anterior
con el término de primer orden, o sea, cuando tenemos el esquema númerico
donde y0 = y(x0 ).
El esquema anterior se conoce por el nombre de esquema o método de Euler y es,
quizá, el método más sencillo para resolver númericamente una EDO de primer orden.
Nótese que dicho esquema necesita en cada paso del valor y(xk ), por tanto cuanto más
cercano sea el valor yk calculado del y(xk ) real más preciso será el método. Obviamente
en cada paso arrastramos el error del cáculo del paso anterior. En efecto, para calcular
112
y1 usamos el valor real y0 pero cuando calculamos y2 , sustituimos el valor exacto y(x1 )
desconocido por su valor aproximado y1 , para calcular y3 sustituimos el valor y(x2 ) por su
valor aproximado y2 , y así sucesivamente.
Veamos algunos ejemplos.
Comenzaremos con una ecuación que sepamos resolver exactamente. Por ejemplo,
estudiemos el problema de valores iniciales
(%i1) x[0]:0;
l:1;Nu:20;h:l/Nu;
x[n]:=x[0]+n*h;
(%o1) 0
(%o2) 1
(%o3) 20
(%o4) 1/20
(%o5) x[n]:=x[0]+n*h
A continuación limpiaremos la variable f que definirá nuestra función f del PVI (5.3.1)
Ya estamos listos para pedirle a M AXIMA que encuentre nuestra solución numérica. Para
ello le pediremos que calcule los valores de y(xk ) mediante la fórmula (5.3.3) y luego
crearemos una lista que podamos representar gráficamente. Para crear la lista usamos el
comando makelist
(%i9) y[k]:=float(y[k-1]+h*f[x[k-1],y[k-1]]);
sol:makelist(float([x[k],y[k]]),k,0,Nu);
(%o9) y[k]:=float(y[k-1]+h*f[x[k-1],y[k-1]])
(%o10) [[0.0,1.0],[0.05,0.95],[0.1,0.905],[0.15,0.86475], ...,
[0.95,0.70470720507062],[1.0,0.71697184481708]]
Los resultados están escritos en la tabla 5.1 o dibujados en la gráfica 5.6 (izquierda).
Para dibujarlos hemos usado el comando plot2d
Comparemos ahora la solución exacta y(x) = 2e−x − 1 + x del PVI con los valores
numéricos que nos da en método de Euler y dibujemos ambas
(%i12) expon(x):=-1+2*exp(-x)+x$
wxplot2d([[discrete,sol],expon(x)],[x,0,1],[style,[points,2,2],
[lines,1,1]],[legend,"y(x) aproximado","y(x) real"],
[xlabel,"x"], [ylabel,"y"])$
(%t13) << Graphics >>
Finalmente, podemos calcular los errores cometidos en cada paso y representarlos gráfi-
camente –ver figura 5.6 (derecha)–.
(%i14) compsol:makelist(float([x[k],abs(y[k]-expon(x[k]))]),k,0,Nu)$
wxplot2d([[discrete,compsol]],[style, [points,2,3]],
[legend,false],[xlabel,"x"], [ylabel,"y(x)-y"])$
(%t15) << Graphics >>
y 0 − 1 − y 2 = 0, y(0) = 0, x ≥ 0.
1 1
y(x) y(x) aproximado
0.95 0.95 y(x) exacto
0.9 0.9
0.85 0.85
y
y
0.8 0.8
0.75 0.75
0.7 0.7
0.65 0.65
0 0.2 0.4 0.6 0.8 1 0 0.2 0.4 0.6 0.8 1
x x
Figura 5.6: Solución numérica para N = 20 (•) (izquierda) y comparación con la solución
exacta y 0 + y = x, y(0) = 1 (línea) (derecha)
0.8 4
y(x) aproximado y(x) aproximado
0.7 y(x) exacto 3.5 y(x) exacto
0.6 3
0.5 2.5
0.4 2
y
y
0.3 1.5
0.2 1
0.1 0.5
0 0
0 0.1 0.2 0.3 0.4 0.5 0.6 0 0.2 0.4 0.6 0.8 1 1.2
x x
Una posibilidad es truncar la serie de Taylor (5.3.2) en el tercer orden, de forma que
tengamos
2
∂f ∂f h
yk+1 = yk + hf (xk , yk ) + (xk , yk ) + f (xk , yk ) (xk , yk ) , y0 = y(x0 ).
∂x ∂y 2
La ecuación anterior se conoce como el método de la serie de Taylor de tres términos y,
aunque es más preciso que el de Euler (se puede probar que es un método de orden 2),
es algo incómodo sobre todo si f es una función “complicada”. Por ello se suele usar una
modificación del mismo.
Para ello escribamos la EDO original y 0 = f (x, y) en el intervalo xk , xk + h en su forma
integral
Z xk +h
y(xk+1 ) = y(xk ) + f (x, y(x))dx.
xk
Para resolver este problema aproximamos la integral mediante un rectángulo de altura
f (xk , yk ) (ver figura 5.8 izquierda)
Z xk +h
f (x, y(x))dx ≈ hf (xk , yk ),
xk
y
f(x,y(x))
11111111111111
00000000000000
f(x,y(x)) k+1
00000000000000
11111111111111
00000000000000
11111111111111
00000000000000
11111111111111
00000000000000
11111111111111
00000000000000
11111111111111
y 00000000000000
11111111111111
00000000000000
11111111111111
y
k 11111111111111
00000000000000
00000000000000
11111111111111
k
00000000000000
11111111111111
00000000000000
11111111111111 00000000000000
11111111111111
00000000000000
11111111111111
00000000000000
11111111111111 00000000000000
11111111111111
00000000000000
11111111111111
xk x k+1 xk x k+1
Figura 5.8: Regla del rectángulo (izquierda) y del trapecio (derecha) para aproximar una
integral
(%i29) kill(x,ym)$
ym[0]:1$ ym[0]:1$ l:1$ Nu:20$ h:l/Nu$
x[0]:0$ x[n]:=x[0]+n*h$
define(f[x,y],-y+x)$
ym[k]:=float(ym[k-1]+(h/2)*(f[x[k-1],ym[k-1]]+
f[x[k], ym[k-1]+h*f[x[k-1],ym[k-1]]]))$
solm:makelist(float([x[k],ym[k]]),k,0,Nu)$
1
y(x) euler
0.95 y(x) euler mejorado
y(x) exacto
0.9
0.85
y
0.8
0.75
0.7
0.65
0 0.2 0.4 0.6 0.8 1
x
wxplot2d([[discrete,sol],[discrete,solm],expon(x)],[x,0,1],
R. Álvarez Nodarse Introducción a M AXIMA CAS 117
Como ejercicio, construir la matriz de errores similar a la de la tabla 5.1 pero para el
caso del método de Euler mejorado (ver resultado en la tabla 5.2).
Antes de terminar este apartado conviene hacer notar que existen muchos métodos
para resolver numéricamente las ecuaciones diferenciales. En general conviene que el mé-
todo usado tenga dos características fundamentales: que sea preciso y estable. Las dos
versiones del método de Runge-Kutta que usa M AXIMA cumplen muy bien ambas carac-
terísticas no así el método de Euler que hemos descrito en este apartado y que suele ser
inestable, no obstante hay problemas donde conviene usar otros métodos adaptados al
tipo de problema a resolver, pero estos quedan fuera del objetivo de estas notas.3
3
EL lector interesado puede consultar la magnífica monografía de A Quarteroni y F. Saleri, Cálculo Científico
con MATLAB y Octave, Springer-Verlag, 2006.
118
Capítulo 6
Vamos a dedicar este apartado a los sistemas de EDOs (SEDOs) lineales, i.e., los siste-
mas de la forma:
0
y1 (x) = a11 (x)y1 (x) + a12 (x)y2 (x) + · · · + a1n (x)yn (x) + b1 (x),
y 0 (x) = a21 (x)y1 (x) + a22 (x)y2 (x) + · · · + a2n (x)yn (x) + b2 (x),
2
..
.
0
yn (x) = an1 (x)y1 (x) + an2 (x)y2 (x) + · · · + ann (x)yn (x) + bn (x).
donde
a11 (x) a12 (x) a13 (x) · · · a1n (x) b1 (x)
a21 (x) a22 (x) a23 (x) · · · a2n (x) b2 (x)
A(x) = .. .. .. .. , B(x) = .. ,
..
. . . . . .
an1(x) an2 (x) an3 (x) · · · ann (x) bn (x)
Cuando B(x) = 0, o sea cuando todas las componentes del vector B son cero, di-
remos que el SEDO es homogéneo, y si al menos una componente de B es no nula, no
homogéneo. En el caso de un sistema homogéneo se tiene el siguiente resultado:
En particular, la solución del PVI, Y 0 = A(x)Y , Y (x0 ) = Y0 se expresa de manera única como
una combinación lineal de las soluciones del sistema homogéneo correspondiente.
119
120
Así que, para encontrar la solución gereral del SEDO Y 0 = A(x)Y , basta encontrar
n soluciones independientes del mismo. Una de las opciones más comunes es buscar la
solución de Y 0 = A(x)Y en la forma
5. Para todas las matrices A, B con AB = BA, exp[x(A + B)] = exp(xA) exp(xB).
del PVI, Y 0 = AY , Y (0) = ei que además son linealmente independientes y por tanto
constituyen una base del espacio de soluciones del sistema homogéneo correspondiente.
Otro concepto importante es el de matriz fundamental: Una matriz V ∈ Rn×n es una
matriz fundamental del sistema Y 0 = AY si sus n columnas son un conjunto linealmente
independiente de soluciones de Y 0 = AY . Obviamente la matriz exponencial es una matriz
fundamental del sistema Y 0 = AY .
Vamos a usar M AXIMA para encontrar la solución de un sistema homogéneo así como
la exponencial de una matriz. Por sencillez nos centraremos en el caso de matrices de 2x2.
matrix(fila1,fila2,...,finaN)
donde fila1, fila2, etc. son los vectores filas (listas de números a1, a2, ... de la forma
[a1,a2,...,aM])3
Veamos como ejemplo la resolución del sistema
0 1 12
Y = Y.
3 1
(%i1) A:matrix([1,12],[3,1]);
(%o1) matrix([1,12],[3,1])
(%i2) kill(y1,y2,x)$
desolve(
['diff(y1(x),x)=y1(x)+12*y2(x),'diff(y2(x),x)=3*y1(x)+y2(x)],
[y1(x),y2(x)]);
(%o3) [y1(x)=((2*y2(0)+y1(0))*%e^(7*x))/2-((2*y2(0)-y1(0))*%e^(-5*x))/2,
y2(x)=((2*y2(0)+y1(0))*%e^(7*x))/4+((2*y2(0)-y1(0))*%e^(-5*x))/4]
y obtenemos la solución general. Nótese que en la salida de M AXIMA aparecen los valores
y1 (0) e y2 (0) que apriori son desconcidos. Si queremos resolver el PVI
0 1 12 1
Y = Y, Y (0) = ,
3 1 2
(%i4) kill(y1,y2,x)$
atvalue(y1(x),x=0,1)$
atvalue(y2(x),x=0,2)$
desolve(
['diff(y1(x),x)=y1(x)+12*y2(x),'diff(y2(x),x)=3*y1(x)+y2(x)],
[y1(x),y2(x)]);
(%o7) [y1(x)=(5*%e^(7*x))/2-(3*%e^(-5*x))/2,
y2(x)=(5*%e^(7*x))/4+(3*%e^(-5*x))/4]
(%i8) kill(y1,y2,x)$
atvalue(y1(x),x=0,1)$
atvalue(y2(x),x=0,0)$
col1:desolve(
['diff(y1(x),x)=y1(x)+12*y2(x),'diff(y2(x),x)=3*y1(x)+y2(x)],
[y1(x),y2(x)]);
(%o11) [y1(x)=%e^(7*x)/2+%e^(-5*x)/2,y2(x)=%e^(7*x)/4-%e^(-5*x)/4]
(%i12) ec1:makelist(second(col1[k]),k,1,length(col1));
(%o12) [%e^(7*x)/2+%e^(-5*x)/2,%e^(7*x)/4-%e^(-5*x)/4]
y luego el PVI
1 12 0
Y0 = Y, Y (0) = ,
3 1 1
(%i13) kill(y1,y2,x)$
atvalue(y1(x),x=0,0)$
atvalue(y2(x),x=0,1)$
col2:desolve(
['diff(y1(x),x)=y1(x)+12*y2(x),'diff(y2(x),x)=3*y1(x)+y2(x)],
[y1(x),y2(x)]);
(%o16) [y1(x)=%e^(7*x)-%e^(-5*x),y2(x)=%e^(7*x)/2+%e^(-5*x)/2]
(%i17) ec2:makelist(second(col2[k]),k,1,length(col2));
(%o17) [%e^(7*x)-%e^(-5*x),%e^(7*x)/2+%e^(-5*x)/2]
Dado que las salidas ec1 y ec2 son vectores filas, los convertimos en columna simple-
mente transponiendo la matriz con el comando transpose
(%i18) define(expA(x),transpose(matrix(ec1,ec2)));
(%o18) expA(x):=matrix([%e^(7*x)/2+%e^(-5*x)/2,%e^(7*x)-%e^(-5*x)],
[%e^(7*x)/4-%e^(-5*x)/4,%e^(7*x)/2+%e^(-5*x)/2])
(%i19) expA(0);
(%o19) matrix([1,0],[0,1])
(%i20) ratsimp(diff(expA(x),x)-A.expA(x));
(%o20) matrix([0,0],[0,0])
(%i21) vec:eigenvectors(A);
(%o21) [[[-5,7],[1,1]],[[[1,-1/2]],[[1,1/2]]]]
(%i22) vec[1]; vec[2];
(%o22) [[-5,7],[1,1]]
(%o23) [[[1,-1/2]],[[1,1/2]]]
es decir
e−5x e7x
Y1 (x) = , Y2 (x) = 1 7x .
− 21 e−5x 2e
(%i32) define(v(x),transpose(matrix(s1(x),s2(x))));
(%o32) v(x):=matrix([%e^(-5*x),%e^(7*x)],[-%e^(-5*x)/2,%e^(7*x)/2])
(%i33) define(e(x),v(x).invert(v(0)));
(%o33) e(x):=matrix([%e^(7*x)/2+%e^(-5*x)/2,%e^(7*x)-%e^(-5*x)],
[%e^(7*x)/4-%e^(-5*x)/4,%e^(7*x)/2+%e^(-5*x)/2])
(%i34) ratsimp(diff(e(x),x)-A.e(x));
(%o34) matrix([0,0],[0,0])
(%i35) expA(x)-e(x);
(%o35) matrix([0,0],[0,0])
Dado que ya sabemos calcular la matriz exponencial ahora podemos resolver fácilmen-
te el problema no homogéneo. Para ello usamos el resultado
Teorema 3 La solución del problema de valores iniciales Y 0 (x) = AY (x) + B(x), Y (x0 ) =
Y0 , cualquiera sea Y0 ∈ Rn existe y es única y se expresa mediante la fórmula
Z x
Y (x) = exp[(x − x0 )A]Y0 + exp[(x − t)A]B(t)dt. (6.2.1)
x0
(%i36) b:transpose([exp(-t),0]);
(%o36) matrix([%e^(-t)],[0])
(%i37) ratsimp(e(x-t).b); expand(%);
define(sol(x),expand(integrate(%, t, 0, x)));
(%o37) matrix([(%e^(-5*x-8*t)*(%e^(12*x)+%e^(12*t)))/2],
[(%e^(-5*x-8*t)*(%e^(12*x)-%e^(12*t)))/4])
(%o38) matrix([%e^(7*x-8*t)/2+%e^(4*t-5*x)/2],
[%e^(7*x-8*t)/4-%e^(4*t-5*x)/4])
(%o39) sol(x):=matrix([%e^(7*x)/16+%e^(-x)/16-%e^(-5*x)/8],
[%e^(7*x)/32-(3*%e^(-x))/32+%e^(-5*x)/16])
4
Recordemos que las operaciones A.B con A*B son distintas. Si bien la primera es la multiplicación habitual
de matrices, la segunda es una multiplicación elemento a elemento. Por ejemplo
1 12 1 1 13 13 1 12
A= ,C= , A.B = pero A ∗ B .
3 1 1 1 4 4 3 1
Más aún si v es un vector 2 × 1, A.v esta bien definido pero A ∗ v no.
R. Álvarez Nodarse Introducción a M AXIMA CAS 125
(%i40) e(x).transpose([0,1]);
(%o40) matrix([%e^(7*x)-%e^(-5*x)],[%e^(7*x)/2+%e^(-5*x)/2])
(%i41) define(solt(x),sol(x)+e(x).transpose([0,1]));
(%o41) solt(x):=matrix([(17*%e^(7*x))/16+%e^(-x)/16-(9*%e^(-5*x))/8],
[(17*%e^(7*x))/32-(3*%e^(-x))/32+(9*%e^(-5*x))/16])
(%i42) solt(0);
(%o42) matrix([0],[1])
(%i43) ratsimp(diff(solt(x),x)-A.solt(x));
(%o43) matrix([%e^(-x)],[0])
donde F (u, v) = 0 es la ecuación implícita que queremos dibujar en los intervalos de las
variables u desde uini hasta ufin y v desde vini hasta vfin. Así, hacemos
5
Quiere decir que las ecuaciones no son independientes.
126
(%i44) load(implicit_plot)$
(%i45) implicit_plot ([
0.5*u+v-log(v*u^0.5)=1.6,0.5*u+v-log(v*u^0.5)=2,0.5*u+v-log(v*u^0.5)=2.3,
0.5*u+v-log(v*u^0.5)=2.5,0.5*u+v-log(v*u^0.5)=3,0.5*u+v-log(v*u^0.5)=3.5],
[u,0.01,7],[v,0.01,6],[legend,"H1=1.6","H2=2.0","H3=2.3","H4=2.5",
"H5=3.0","H6=3.5"])$
6
H1=1.6
H2=2.0
5 H3=2.3
H4=2.5
H5=3.0
H6=3.5
4
3
v
0
1 2 3 4 5 6 7
u
Figura 6.1: Trayectorias definidas por el sistema (6.3.1) para α = 1/2 y H = 1,6, 2, 2.3,
2.5, 3 y 3.5.
Para el sistema (6.3.1) no funciona ninguno de los métodos analíticos discutidos ante-
riormente así que tenemos que resolverlo numéricamente. Para ello usaremos la orden rk
que discutimos en la sección 5.2, página 5.2, pero ahora para un sistema de ecuaciones
diferenciales cuya sintaxis es, en general,
rk([EDO1,...,EDOm],[y1,...,ym],[vini1,...,vinitm],[x,x0,xmax,paso])
La salida de este comando es una lista con tantas entradas como iteraciones y cada entrada
de esa lista es a su vez una lista de m + 1 elementos donde el primero es el valor de la x el
segundo es el valor de y1 evaluada en dicho x, el tercero el de y2 en x y así sucesivamente.
Así pues, tenemos
(%i6) load(dynamics)$
(%i7) kill(a,u,v,sol)$ a:0.5;
sol:rk([u*(1-v),a*v*(u-1)],[u,v],[0.4,0.2],[t,0,40,0.02])$
(%o8) 0.5
A continuación construimos las listas que vamos a representar: la los valores de (xk , uk ) y
(xk , vk ), respectivamente. Como antes, usamos el comando makelist.
(%i10) u:makelist([sol[k][1],sol[k][2]],k,1,length(sol))$
v:makelist([sol[k][1],sol[k][3]],k,1,length(sol))$
ciclo:makelist([sol[k][2],sol[k][3]],k,1,length(sol))$
5 3.5
u u vs v
v
3
4
2.5
3 2
u,v
1.5
2
1
1
0.5
0 0
0 5 10 15 20 25 30 35 40 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5
t u
Figura 6.2: Las soluciones u y v del sistema (6.3.1) para α = 1/2, u(0) = 0,4 y v(0) = 0,2.
Vamos a discutir en este apartado una herramienta muy útil para el estudio de las
EDOs: los denominados campos de direcciones. El campo de direcciones es esencialmente
una gráfica donde se representan las soluciones de nuestra ecuación y donde se incluyen,
mediante flechas, las pendientes de las tangentes a los distintos puntos de curva que define
la solución (trayectoria).
Uno de los comandos más versátiles es plotdf lo que requiere tener instalado el X MA -
XIMA (no basta con M AXIMA o el WXMAXIMA). La orden tiene un sinnúmero de opciones
y la ventana que se abre es interactiva. Pinchando en distintas zonas aparecen las tra-
yectorias correspondientes. Como ejemplo veamos el campo de direcciones del sistema
(6.3.1). La orden que viene a continuación solo pinta la trayectoria cerrada que está en
el primer cuadrante, las restantes se obtienen al pinchar sobre la ventana emergente. Así,
representamos el campo de direcciones de nuestro sistema (6.3.1)
128
(%i17) kill(all)$
(%i1) load("plotdf")$
(%i2) plotdf([x*(1-y),a*y*(x-1)],[parameters,"a=.5"],
[trajectory_at,0.4,0.2],[xradius,5],[yradius,5])$
Finalmente, si incluimos la opción sliders nos aparece en la ventana una paleta para
variar el parámetro a del sistema.
(%i3) plotdf([x*(1-y),a*y*(x-1)],[parameters,"a=.5"],
[sliders,"a=0.2:0.8"],[trajectory_at,0.6,3.1],
[x,-2,8],[yradius,5]);
Figura 6.3: Campo de direcciones para el modelo para el sistema (6.3.1). A la derecha
vemos una captura de la pantalla del plotdf de openmath (contenido en X MAXIMA)
M AXIMA también cuenta con el paquete drawdf para representar campos de direc-
ciones. Aparte de las distintas opciones propias de drawdf también se pueden usar las
opciones heredades del paquete draw. Veamos como ejemplo dos gráficas del campo de
direcciones del sistema (6.3.1) que ya dibujamos con plotdf. La primera secuencia tiene
pocas opciones mientras que en la segunda agregamos una serie de opciones extra. Da-
da la gran cantidad de las mismas es recomendable revisar la documentación general del
paquete drawdf. Las salidas las podemos ver en la figura 6.4.
(%i4) kill(all)$
(%i1) load("drawdf")$
(%i2) drawdf([x*(1-y),.5*y*(x-1)],[x,-5,5], [y,-5,5], line_width = 3,
solns_at([0.6,3.1],[0.6,2.1],[-0.6,3.1],[-0.6,2.1],[0.6,-3.1],
[0.6,-2.1],[-0.6,-3.1],[-0.6,-2.1]), points_joined = false,
point_type = filled_circle, point_size = 3,color=blue,duration = 30,
points([[0.6,3.1],[-0.6,3.1],[0.6,-3.1],[-0.6,-3.1],
[0.6,2.1],[-0.6,2.1],[0.6,-2.1],[-0.6,-2.1]]))$
(%i3) drawdf([x*(1-y),.5*y*(x-1)],[x,-5,5], [y,-5,5],
R. Álvarez Nodarse Introducción a M AXIMA CAS 129
2
2
0 0
y
-2 -2
-4
-4
-4 -2 0 2 4
-4 -2 0 2 4 x
Figura 6.4: Campo de direcciones para el modelo para el sistema (6.3.1) usando drawdf.
A la izquierda sin opciones y a la derecha con varias opciones extra.
Por último mostramos como dibujar con diferentes colores varias trayectorias a la vez
e incluyendo el nombre de cada una de ellas de forma automática:
Campo de direcciones del sistema Lotka-Volterra Campo de direcciones del sistema Lotka-Volterra
5 5
sol. en (2,1/6) sol. en (2,1/6)
sol. en (2,2/6) sol. en (2,2/6)
4 sol. en (2,3/6) 4 sol. en (2,3/6)
sol. en (2,4/6) sol. en (2,4/6)
sol. en (2,5/6) sol. en (2,5/6)
3 3
y
y
2 2
1 1
0 0
0 1 2 3 4 5 0 1 2 3 4 5
x x
Figura 6.5: Campo de direcciones para el modelo para el sistema (6.3.1) con 5 trayectorias
en el primer cuadrante. A la derecha se representa únicamente las trayectorias.
Consideremos ahora otro grupo muy importante de EDOs: las EDOs lineales con coefi-
cientes constantes de orden mayor que 1 definidas por la ecuación:
y (n) (x) + an−1 (x)y (n−1) (x) + · · · + a1 (x)y 0 (x) + a0 (x)y(x) = f (x). (6.4.1)
(n−1)
y(x0 ) = y0 , y 0 (x0 ) = y00 , ... y (n−1) (x0 ) = y0 ,
Para estudiar las propiedades de las EDOs lineales de orden n vamos a introducir unas
nuevas funciones z1 (x), . . . zn (x) de forma que
dzn
z1 (x) = y(x) = −an−1 zn − an−2 zn−1 − · · · − a0 z1 + f,
z2 (x) = y 0 (x)
dx
dzn−1
z3 (x) = y 00 (x)
= zn ,
.. ⇒ dx
. ..
.
zn−1 (x) = y (n−2) (x)
dz1
= z2 .
zn (x) = y (n−1) (x)
dx
R. Álvarez Nodarse Introducción a M AXIMA CAS 131
Es decir, una EDO del tipo (6.4.1) es equivalente al siguiente sistema lineal de ecuaciones:
0 1 0 ··· 0 0
z1 z1 0
0 0 1 ··· 0 0
z2
.. .. .. .. ..
z2 0
d ..
.. . .. ..
=
. . . . .
+
,
dx
. . .
zn−1
0 0 0 ··· 0 1
zn−1
0
0 0 0 ··· 0 1
zn zn f (x)
−a0 −a1 −a2 · · · −an−2 −an−1
o en forma matricial Z 0 (x) = AZ(x) + F (x). Nótese que cuando f (x) ≡ 0, el sistema
anterior se transforma en un sistema homogéneo.
Lo anterior tiene una implicación evidente: toda la teoría de las ecuaciones lineales
(6.4.1) se puede construir a partir de la teoría de los sistemas lineales y por tanto el estudio
con M AXIMA del apartado anterior se puede usar para resolver este tipo de ecuaciones. No
obstante, para el caso N = 2, caso de especial relevancia por sus múltiples aplicaciones
prácticas, M AXIMA cuenta con el comando ode2, que ya usamos antes, y que combinado
con el comando ic2 resuelve ecuaciones lineales de orden 2. La orden sintaxis de la orden
ic2 es
(%i1) eq1:'diff(y,x,2)-2*'diff(y,x,1)+2*y=x^2-1;
(%o1) 'diff(y,x,2)-2*('diff(y,x,1))+2*y=x^2-1
(%i2) ode2(eq1,y,x);
(%o2) y=%e^x*(%k1*sin(x)+%k2*cos(x))+(x^2+2*x)/2
(%i3) ic2(%,x=0,y=0,'diff(y,x)=2);
(%o3) y=%e^x*sin(x)+(x^2+2*x)/2
También podemos usar el comando desolve, aunque en este caso tenemos que escribir
explícitamente tanto la variable dependiente como la independiente. En conjunto con la
orden atvalue también nos da la correspondiente solución:
(%i4) eq2:'diff(y(x),x,2)-2*'diff(y(x),x,1)+2*y(x)=x^2-1;
(%o4) 'diff(y(x),x,2)-2*('diff(y(x),x,1))+2*y(x)=x^2-1
(%i5) atvalue(y(x),x=0,0)$
atvalue('diff(y(x),x),x=0,2)$
desolve(eq2,y(x));
(%o7) y(x)=%e^x*sin(x)+x^2/2+x
(%i8) eq3:x*'diff(y,x)^2-(1+x*y)*'diff(y,x)+y=0;
(%o8) x*('diff(y,x,1))^2-(x*y+1)*('diff(y,x,1))+y=0
(%i9) ode2(eq3,y,x);
(%t9) x*('diff(y,x,1))^2-(x*y+1)*('diff(y,x,1))+y=0
"first order equation not linear in y'"
(%o9) false
(%i10) load('contrib_ode)$
define: warning: redefining the built-in function lcm
(%i11) contrib_ode(eq3,y,x);
(%t11) x*('diff(y,x,1))^2-(x*y+1)*('diff(y,x,1))+y=0
"first order equation not linear in y'"
(%o11) [y=log(x)+%c,y=%c*%e^x]
Como ejercicio comprobar que efectivamente las funciones obtenidas son solución de la
EDO correspondiente.
Otra opción es resolver numéricamente las correspondientes ecuaciones diferenciales,
como es el caso de la ecuación y 00 − 2xy 0 + 2y = 0, que es imposible resolver usando los
tres comandos anteriores.
(%i12) kill(all)$
(%i1) eq4:'diff(y(x),x,2)-2*x*'diff(y(x),x,1)+2*y(x)=0;
(%o1) 'diff(y(x),x,2)-2*x*('diff(y(x),x,1))+2*y(x)=0
(%i2) ode2(eq4,y,x);
(%t2) 'diff(y(x),x,2)-2*x*('diff(y(x),x,1))+2*y(x)=0
"not a proper differential equation"
(%o2) false
(%i5) atvalue(y(x),x=0,1)$ atvalue('diff(y(x),x),x=0,0)$
desolve(eq4,y(x));
(%o5) y(x)=ilt( ... )
(%i6) load('contrib_ode)$
(%i7) contrib_ode(eq4,y,x);
(%o7) false
En este caso, al igual que en todos, podemos recurrir al comando rk del paquete
dynamics (ver página 6.3) pero antes hay que convertir nuestra EDO de orden 2 en un
sistema lineal. Para ello hacemos el cambio z = y 0 de donde se tiene
0
00 0 y = z,
y − 2xy + 2y = 0 ⇔
z 0 = 2xz − y.
(%i8) load(dynamics)$
(%i9) sol:rk([z,2*x*y-y],[y,z],[1,0],[x,0,2,0.02])$
valy:makelist([sol[k][1],sol[k][2]],k,1,length(sol))$
wxplot2d([discrete,valy],[legend, "y"],
[xlabel, "x"], [ylabel, "x"],[color,blue])$
(%t11) << Graphics >>
2 5
0 0
-5
-2
-10
-4
-15
y'
x
-6
-20
-8
-25
-10 -30
-12 -35
0 0.5 1 1.5 2 -12 -10 -8 -6 -4 -2 0 2
x y
Figura 6.6: La solución (izquierda) del PVI y 00 − 2xy 0 + 2y = 0 con y(0) = 1 e y 0 (0) = 0 en
el intervalo [0, 2] y su correspondiente diagrama (y, y 0 ) (derecha).
runge2(f,x0,xf,h,y0,dy0)
(%i12) load(diffeq)$
(%i13) f(t,y,dy) := 2*x*dy - 2*y $
(%i14) res: runge2(f,0,2,0.01,1,0)$
wxplot2d([discrete,res[1],res[2] ],[legend, "y"],
[xlabel, "x"], [ylabel, "x"],[color,blue])$
(%i16) wxplot2d([discrete,res[1],res[3]],[legend, "y'"],
[xlabel, "x"], [ylabel, "y'"],[color,blue])$
(%i17) wxplot2d([discrete,res[2],res[3] ],[legend, "y"],
[xlabel, "y"], [ylabel, "y'"],[color,blue])$
134
σ(x)y 00 + τ (x)y 0 + λy = 0,
(%i1) eqh:x*(1-x)*'diff(y,x,2)+(3/2-2*x)*'diff(y,x)+2*y=0;
(%o1) (1-x)*x*('diff(y,x,2))+(3/2-2*x)*('diff(y,x,1))+2*y=0
(%i2) ode2(eqh,y,x);
(%o2) false
(%i3) load('contrib_ode)$
(%i4) odelin(eqh,y,x);
(%o4) {gauss[a](-1,2,3/2,x),gauss[b](-1,2,3/2,x)}
(%i5) contrib_ode(eqh,y,x);
(%o5) [y=gauss[b](-1,2,3/2,x)*%k2+gauss[a](-1,2,3/2,x)*%k1]
y que son las soluciones (alrededor del cero) de la ecuación hipergeométrica de Gauss
Hay que destacar que M AXIMA no tiene definidas las funciones gauss_a y gauss_b, sim-
plemente las reconoce. Si queremos trabajar con ellas tenemos que definir las correspon-
dientes series de potencias o usar la orden hypergeometric ([<a1>, ..., <ap>],[<b1>,
... ,<bq>], x) que define la función hipergeométrica
∞
(a1 )k (a2 )k · · · (ap )k xk
X
a1 , a2 , . . . , ap
F
p q x = , (6.4.5)
b1 , b2 , . . . , bq (b1 )k (b2 )k · · · (bq )k k!
k=0
que usaremos luego para comprobar si son correctas las soluciones encontradas por M A -
XIMA . Definamos ahora las dos soluciones linealmente independientes de la ecuación
(6.4.4). Comenzamos con la primera
Para la segunda solución los parámetros a1 y a2 no son enteros negativos así que procede-
remos de otro modo. Para ello cargamos el paquete hypergeometric y usamos el coman-
do hypergeometric_simp que intenta escribir la función hipergeométrica en términos de
otras funciones de M AXIMA.
(%i21) wxplot2d([y1(x),y2(x)],[x,0.01,.95],[legend,"y1","y2"]);
(%t21) (Graphics)
Veamos ahora el problema de valores iniciales (PVI) para la ecuación (6.4.4) con las con-
diciones y(1/2) = 0, y 0 (1/2) = 1 (nótese que en el punto x = 0 la segunda solución tiende
a infinito). Para ello definimos las derivadas de las soluciones
(%i22) define(dy1(x),diff(y1(x),x));
define(dy2(x),radcan(diff(y2(x),x)));
(%o22) dy1(x):=-4/3
(%o23) dy2(x):=(8*x^2-4*x-1)/(2*sqrt(1-x)*x^(3/2))
(%i25) define(sol(x),alpha*y1(x)+beta*y2(x))$
define(dsol(x),diff(alpha*y1(x)+beta*y2(x),x))$
Usando las funciones anteriores podemos resolver el PVI y definir la solución general
A continuación comprobamos que la solución cumple con todas las condiciones requeri-
das, i.e., las condiciones iniciales y la propia ecuación diferencial:
(%i33) soly(1/2);
diff(soly(x),x)$ ev(%,x=1/2);
(%o31) 0
(%o33) 1
(%i34) ecuh(soly(x)), ratsimp;
(%o34) 0
y la representamos
R. Álvarez Nodarse Introducción a M AXIMA CAS 137
Vamos ahora a resolver el mismo PVI numéricamente usando el comando rk (ver pá-
gina 126)
10 0.3
y1 solución y(x)
y2 solución numérica
8 0.25
6 0.2
4 0.15
2 0.1
0 0.05
-2 0
0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95
x x
Figura 6.7: Las dos soluciones linealmente independientes de la EDO (6.4.4) (izquierda)
y comparación de las soluciones numéricas y analíticas del PVI.
(%i1) eq5:x*(1-x)*'diff(y,x,2)+(1/2-2*x)*'diff(y,x)+1/2*y=0;
(%o1) (1-x)*x*('diff(y,x,2))+(1/2-2*x)*('diff(y,x,1))+y/2=0
(%i3) load (hypergeometric) $
load('contrib_ode)$
(%i4) sol5:odelin(eq5,y,x);
(%o4) {gauss[a](sqrt(3)/2,-sqrt(3)/2,1/2,x)/sqrt(x-1),
gauss[b](sqrt(3)/2,-sqrt(3)/2,1/2,x)/sqrt(x-1)}
√
Si nos√interesa trabajar en el intervalo [0, 1) está claro que debemos reescribir la x−1
como 1 − x. Así, para la primera solución tenemos
138
y para la segunda
(%i13) (x)^(1-c)*hypergeometric([a-c+1,b-c+1],[2-c],x)/sqrt(1-x)$
hypergeometric_simp(%), radcan$
sol2:%;
(%o15) sin(sqrt(3)*asin(sqrt(x)))/(sqrt(3)*sqrt(1-x))
Como ejercicio comprobar que ambas son soluciones de la ecuación (6.4.6) y representar-
las gráficamente.
Para terminar este apartado vamos a representar gráficamente los cinco primeros po-
(1/5,0)
linomios de Jacobi Pn (x). Usaremos el comando draw
(%i30) load(draw)$
(%i31) draw2d( font="Arial",font_size=27,line_width=5,line_type=dots,
color=grey,explicit(0,x,-1.0,1.0), parametric(0,t,t,-1,1),
color=grey,explicit(0,x,-1.0,1.0),line_type=solid,line_width=8,
color=green, explicit( jacobi_p (1, 1/5, 0, x),x,-1.0,1.0),
color=dark_violet, explicit( jacobi_p (2,1/5,0,x),x,-1.0,1.0),
color=navy, explicit( jacobi_p (3, 1/5, 0, x),x,-1.0,1.0),
color=blue, explicit( jacobi_p (4, 1/5, 0, x),x,-1.0,1.0),
color=red, explicit( jacobi_p (5, 1/5, 0, x),x,-1.0,1.0) )$
(%i32) colors:[green,dark_violet,navy,blue,red];
(%i33) polijac:makelist([key = concat("Pol. Jacobi de grado ",k),
color=colors[k], explicit( jacobi_p (k, 1/5, 0, x),
x,-1.0,1.0)],k,1,5)$
1.5 1.5
Pol. Jacobi de grado 1
Pol. Jacobi de grado 2
Pol. Jacobi de grado 3
Pol. Jacobi de grado 4
1 1
Pol. Jacobi de grado 5
0.5 0.5
0 0
-0.5 -0.5
-1 -1
-1 -0.5 0 0.5 1 -1 -0.5 0 0.5 1
(1/5,0)
Figura 6.8: Los gráficos de los polinomios de Jacobi Pn (x), n = 1, 2, 3, 4, 5.
file_name="/home/renato/poljac1", terminal=pdf,dimensions=[1000,1000]
En la figura 6.8 (izquierda) están representados los primeros cinco polinomios de Jacobi
(1/5,0)
Pn (x) incluyendo los dos ejes de coordenadas. En la figura de la derecha mostramos
la salida de la última secuencia donde se muestra el código de colores usado para cada
uno de los polinomios.
En el próximo apartado veremos como resolver las EDOs del tipo (6.4.3) usando series
de potencias.
140
Capítulo 7
Sea la EDO
y 00 + p(x)y 0 + q(x)y = f (x). (7.1.1)
El objetivo es resolver la EDO anterior cuando las funciones p(x), q(x) y f (x) dependen
de x. Para ello vamos a suponer que dichas funciones son “razonablemente” buenas en
un entorno de cierto punto x0 de la recta real y buscaremos la solución como una serie de
potencias, es decir en la forma
∞
X
y(x) = ak (x − x0 )k , ak ∈ R. (7.1.2)
k=0
Las funciones que se pueden expresar mediante una serie de potencias convergentes en
todo un entorno de x = x0 como la anterior se denominan funciones analíticas en x = x0 .
Por sencillez supondremos x0 = 0, ya que en caso que x0 6= 0 siempre podemos realizar el
cambio de variable z = x − x0 de forma que en la nueva variable z0 = 0.
La idea del método es sustituir la serie y(x) (7.1.2) en (7.1.1) e igualar los coeficientes
de las potencias. De esta forma obtenemos un sistema de ecuaciones para los coeficientes
an en (7.1.2). Es importante que la serie converja en todo un entorno de x0 , de esta forma
tenemos asegurada la existencia de la solución al menos en cierta región.
Como
P∞ejemplo resolvamos la EDO y 00 − 2xy 0 − 2y = 0. Para ello buscamos la solución
y(x) = k=0 ak xk , la sustituimos en la EDO y usamos que
∞ ∞ ∞ ∞
d X X X X
y 0 (x) = ak xk = (ak xk )0 = kak xk−1 = (n + 1)an+1 xn ,
dx
k=0 k=0 k=0 n=0
∞ ∞ ∞
00 d 0 d X
k−1
X
k−2
X
y (x) = y (x) = kak x = k(k − 1)ak x = (n + 1)(n + 2)an+2 xn
dx dx
k=0 k=0 n=0
lo que nos da
∞
X ∞
X ∞
X
k−1 k
k(k − 1)ak x −2 kak x − 2 ak xk = 0,
k=0 k=0 k=0
141
142
que equivale a
∞
X
[(n + 1)(n + 2)an+2 − (2n + 2)an ] xn = 0.
n=0
Como (xn )
n es una sucesión de funciones linealmente independientes la igualdad a cero
tiene lugar si y sólo si (n + 1)(n + 2)an+2 − (2n + 2)an = 0, de donde tenemos
2
an+2 = an , n ≥ 0. (7.1.3)
n+2
La ecuación anterior define todos los valores de an en función de a0 y a1 . En efecto, si
sabemos a0 , la recurrencia anterior permite calcular los valores a2 , a4 , . . . a2k , k ∈ N y si
conocemos a1 entonces podemos calcular a3 , a5 , . . . a2k+1 , k ∈ N. Así, tenemos
2n
2 2 2 a0
a2n = a2n−2 = a2n−4 = · · · = a0 = ,
2n 2n 2n − 2 (2n)(2n − 2) · · · 2 n!
2n
2 2 2
a2n+1 = a2n−1 = a2n−3 = · · · = a1 ,
2n + 1 2n + 1 2n − 1 (2n + 1)(2n − 1) · · · 3 · 1
es decir 2n /(2n + 1)!! a1 , donde (2n + 1)!! = 1 · 3 · 5 · · · (2n + 1). De esta forma obtenemos
dos soluciones linealmente independientes (una tiene solo potencias pares y la otra solo
impares)
∞ ∞
X x2n X 2n x2n+1
y(x) = a0 + a1 .
n! (2n + 1)!!
n=0 n=0
2
La primera suma es fácilmente reconocible como la serie de potencias de la función ex , no
así la segunda que en general no se expresa como combinación de funciones elementales.
De la expresión explícita de las dos sumas anteriores es fácil comprobar que el radio de
convergencia es infinito.
Resolvámoslo ahora con M AXIMA. Para ello definimos la sucesión bn[n] solución de
(7.1.3) cuando a0 = 1 y a1 = 0.
(%i1) bn[0]:1;bn[1]:0;
bn[n]:=2/(n)*bn[n-2];
(%o1) 1
(%o2) 0
(%o3) bn[n]:=2/n*bn[n-2]
(%i4) solaprox(x,p):=sum(bn[n]*x^n,n,0,p);
(%o4) solaprox(x,p):=sum(bn[n]*x^n,n,0,p)
(%i5) solaprox(x,10);
(%o5) x^10/120+x^8/24+x^6/6+x^4/2+x^2+1
(%i6) bi[0]:0;bi[1]:1;
bi[n]:=2/(n)*bi[n-2];
(%o6) 0
(%o7) 1
(%o8) bi[n]:=2/n*bi[n-2]
R. Álvarez Nodarse Introducción a M AXIMA CAS 143
(%i9) solaproxi(x,p):=sum(bi[n]*x^n,n,0,p);
(%o9) solaproxi(x,p):=sum(bi[n]*x^n,n,0,p)
(%i10) solaproxi(x,10);
(%o10) (16*x^9)/945+(8*x^7)/105+(4*x^5)/15+(2*x^3)/3+x
(%i11) wxplot2d([solaprox(x,10),solaproxi(x,10)],[x,-2,2],
[legend,"y par","y impar"],[xlabel,"x"],[ylabel,"y"]);
(%t11) << Graphics >>
En el caso que nos ocupa el comando ode2 es capaz de resolver la EDO. En particular
resolveremos el PVI cuando y(0) = 1 e y 0 (0) = 0
(%o11)(%i12) ed:'diff(y,x,2)-2*x*'diff(y,x)-2*y=0;
(%o12) 'diff(y,x,2)-2*x*('diff(y,x,1))-2*y=0
(%i13) ode2(ed,y,x);
ic2(%,x=0,y=1,diff(y,x)=0);
(%o13) y=(sqrt(%pi)*%k1*%e^x^2*erf(x))/2+%k2*%e^x^2
(%o14) y=%e^x^2
(%i15) define(soana(x),rhs(%));
(%o15) soana(x):=%e^x^2
(%i16) wxplot2d([solaprox(x,10),soana(x)],[x,-2,2],
[legend,"y aproximada","y exacta"],[xlabel,"x"],[ylabel,"y"]);
(%t16) << Graphics >>
(%o16)(%i17) load(dynamics)$
(%i18) solnum: rk([z,2*x*z+2*y],[y,z],[1,0],[x,0,2,0.02])$
soly:create_list([solnum[i][1],solnum[i][2]],i,1,length(solnum))$
(%i20) wxplot2d([solaprox(x,10),soana(x),[discrete,soly]],
[x,0,2],[legend,"y aproximada","y exacta","y numerica"])$
(%t20) << Graphics >>
60 60
y par y aproximada
50 y impar y exacta
50 y numérica
40
30
40
20
10 30
y
0
20
-10
-20
10
-30
-40 0
-2 -1.5 -1 -0.5 0 0.5 1 1.5 2 0 0.5 1 1.5 2
x x
(%i1) kill(y,x,a,des,Aa,N,seriep)$
seriep(x,p):=sum(a[n]*x^n,n,0,p)$
N:12$
coeff(b*x^4+a^2*x^2-2*sin(x)+3*sin(x)^3,x,4)
coeff(b*x^4+a^2*x^2-2*sin(x)+3*sin(x)^3,sin(x),3)
(%i4) define(des(x),expand(diff(seriep(x,N),x,2)-2*x*diff(seriep(x,N),x,1)
-2*seriep(x,N)))$
siseq1:append([a[0]-1=0,a[1]=0,des(0)=0],
R. Álvarez Nodarse Introducción a M AXIMA CAS 145
makelist(coeff(des(x),x^k)=0 ,k,1,N-2))$
incog:makelist(a[k],k,0,N)$
coef1:solve(siseq1,incog);
(%o7) [[a[0]=1,a[1]=0,a[2]=1,a[3]=0,a[4]=1/2,a[5]=0,
a[6]=1/6,a[7]=0,a[8]=1/24,a[9]=0,a[10]=1/120,a[11]=0,a[12]=1/720]]
El siguiente paso consiste en construir el polinomio de forma que podamos trabajar con
él. para ello construimos la lista de los coeficientes a partir de la salida de solve usamos
el comando apply ("+", lista )1 que suma los elementos de la lista lista
siseq2:append([a[0]=0,a[1]-1=0],
makelist(coeff(des(x),x,k)=0 ,k,0,N-2))$
incog:makelist(a[k],k,0,N)$
coef2:solve(siseq2,incog);
(%o23) [[a[0]=0,a[1]=1,a[2]=0,a[3]=2/3,a[4]=0,a[5]=4/15,a[6]=0,
a[7]=8/105,a[8]=0,a[9]=16/945,a[10]=0,a[11]=32/10395,a[12]=0]]
listacoef2:makelist( rhs(coef2[1][k]),k,1,N+1)$
listpot:makelist(x^k,k,0,N)$
define(ser2(x), apply ("+", listacoef2*listpot));
(%o26) ser2(x):=(32*x^11)/10395+(16*x^9)/945+(8*x^7)/105+
(4*x^5)/15+(2*x^3)/3+x
Como ejercicio, dibujar ambas funciones y compararlas con las obtenidas al principio del
apartado 7.1.
1
Este comando ya lo comentamos en el apartado 4.5.
146
Capítulo 8
El objetivo de esta sección es presentar algunos problemas sencillos que podemos re-
solver usando M AXIMA. En algunos casos se incluye la solución detallada mientras que
otros se proponen como ejercicio.
8.1.1. Ejemplo 1
Una pregunta interesante es saber la sucesión de las ponencias de una matriz tiene
algún límite o no. Una manera de saberlo es estudiando si la norma de las potencias de la
matriz tiene límite o no. Definamos la función Ak , k ∈ N, que calcula la potencia k-ésima
de A (no confundir con la orden M^k)
147
148
1.6
1.4
1.2
norma de Mbk
1
0.8
0.6
0.4
0.2
0
-0.2
0 5 10 15 20 25 30 35 40 45 50
k
Como np (A) es una norma1 ello indica que si np (A) → 0 entonces A → 0. Veamos un
ejemplo. Definimos una cierta matriz Mb y calculamos las normas de sus potencias para
ver si la sucesión Mb^^n tiene límite
Como se en la figura 8.1 la norma de nuestra matriz se acerca a cero, lo que efectivamente
indica que la propia matriz es cercana a matriz nula. Lo comprobamos calculando la norma
de Mb^200 y la potencia 200 de la matriz:
(%i8) float(n(powerM(Mb,200),2));
(%o8) 3.377091873620356*10^-9
(%i9) powerM(float(Mb),200);
(%o9) matrix(
[2.368893230664782*10^-6,1.127049380923565*10^-5,1.532047950973439*10^-5],
[4.979067672874238*10^-7,2.368893230664788*10^-6,3.220141088353051*10^-6],
[6.762296285541401*10^-6,3.217300697044229*10^-5,4.373418790694773*10^-5])
8.1.2. Ejemplo 2
(%i10) av:abs(float(eigenvalues(Mb)));
(%o10) [[0.2214571281540186,0.2214571281540186,0.9515408852827707],
[1,1,1]]
1
Véase, por ejemplo, [7].
R. Álvarez Nodarse Introducción a M AXIMA CAS 149
1.7 1.4x106
1.6 1.2x106
1.5 1x106
norma de Mbk
norma de Mbk
1.4 800000
1.3 600000
1.2 400000
1.1 200000
1 0
0 5 10 15 20 25 30 35 40 45 50 0 2 4 6 8 10 12 14 16
k k
Pasemos a nuestro segundo problema. Una pregunta que podemos hacernos es si va-
riando los valores de la matriz podemos conseguir que los autovalores sean, en valor abso-
luto, mayores que 1. Esto se puede relacionar con la estabilidad de modelos asociados a la
matriz Mb. Propongámonos resolver el siguiente problema: Mientras todos los autovalores
de Mb sean, en valor absoluto, menores que 1, incrementar el valor Mb2,1 de 0.1 en 0.1
hasta que al menos uno sea mayor. Para eso hay que hacer un bucle con do pero en vez de
usar la orden for debemos usar la orden while.
(%o11) kill(Mb,av)$
Mb: matrix(
[0,0,1/3],[1/5,0,0],[0,7/10,9/10])$
av:abs(float(eigenvalues(Mb))); kk:0$
while av[1][1]<1.0 and av[1][2]<1.0 and av[1][3]<1.0
do (Mb[2,1]:Mb[2,1]+.01, kk:kk+1, av:abs(float(eigenvalues(Mb))))$
Mb; kk; abs(float(eigenvalues(Mb)));
(%o13) [[0.221457128154018,0.221457128154018,0.951540885282770],[1,1,1]]
(%o16) matrix([0,0,1/3],[0.4300000000000002,0,0],[0,7/10,9/10])
(%o17) 23
(%o18) [[0.316710410677950,0.316710410677950,1.00027764286021],[1,1,1]]
Como vemos en este ejemplo, en 23 pasos obtenemos una matriz que tiene al menos
un autovalor mayor que uno. Aquí la orden while condiciones do orden lo que hace es
ejecutar la orden orden mientras la salida del while sea true.
Hecho esto podemos dibujar la evolución de las normas de la sucesión M1^^k de po-
tencias de la matriz resultante:
(%i21) M1:Mb$
evo:makelist( n(powerM(M1,k),2), k,1,50,1)$
wxplot2d([discrete,evo],[style,points])$
(%t23) << Graphics >>
(%i22) kill(Mb,av)$
Mb: float(matrix( [0,0,1/3], [1/5,0,0], [0,7/10,9/10]) )$
av:abs(float(eigenvalues(Mb))); kk:0$
while av[1][1]<1.0 or av[1][2]<1.0 or av[1][3]<1.0 do
( Mb[2,1]:Mb[2,1]+.01, kk:kk+1,
av:abs(float(eigenvalues(Mb))) )$
Mb; av:abs(float(eigenvalues(Mb))); kk;
(%o24) [[0.221457128154018,0.221457128154018,0.951540885282770],[1,1,1]]
(%o27) matrix([0,0,0.33333333333333],[6.6299999999999,0,0],[0.0,0.7,0.9])
(%o28) [[1.00010345656338,1.00010345656338,1.5466799550598],[1.0,1.0,1.0]]
(%o29) 643
(%i30) M2:Mb$
evo:makelist( n(powerM(M2,k),2) ,k,1,15,1)$
(%i32) wxplot2d([discrete,evo],[style,points],[xlabel,"k"],
[ylabel,"norma de Mb^k"])$
(%t32) << Graphics >>
(%i33) powerM(M2,100);
(%o33) matrix(
[1.983401672306752*10^18,4.626979803000077*10^17,1.022350987680987*10^18],
[8.502051794474104*10^18,1.983401672306753*10^18,4.382410870555725*10^18],
[9.203062828167024*10^18,2.146937074130075*10^18,4.743749339045423*10^18])
(%i34) n(powerM(M2,100),2);
(%o34) 2.124263271158474*10^38
Notemos que en el segundo caso hemos tenido que hacer muchas más iteraciones: 643
en concreto. Eso nos dice que podría ocurrir que nunca obtengamos todos los autovalores
mayores que 1, por tanto es conveniente que el bucle terminara después de un número
de pasos determinado. ¿Cómo se puede hacer esto? Esta pregunta la dejaremos como
ejercicio al lector.
Como último ejercicio de este apartado realizar el mismo estudio cambiando el ele-
mento Mb3,1 en vez del elemento Mb2,1 .
Sea f (x) una función continua definida en el intervalo [a, b]. El objetivo es encontrar
Z b
fórmulas aproximadas para calcular la integral f (x) dx. En caso de conocer la primitiva
a
F (x) es evidente que podemos encontrar el valor exacto de la integral utilizando el Teore-
Z b
ma fundamental del cálculo integral: f (x) dx = F (b) − F (a). Sin embargo no siempre
a
2
esto es posible. Por ejemplo, para la función f (x) = e−x no existe ninguna primitiva que
podamos escribir utilizando funciones elementales. Existen una gran cantidad de métodos
para resolver este problema.
R. Álvarez Nodarse Introducción a M AXIMA CAS 151
donde el error R(ξ), si f tiene primera y segunda derivadas continuas en [a, b], se expresa
de la forma
(b − a)2 00
R(ξ) = f (ξ), ξ ∈ [a, b].
24
y y
f(x) f(x)
x x
Figura 8.3: Aproximación de una integral por el método de los rectángulos. A la izquierda
vemos el área bajo la curva que queremos calcular. A la derecha, la aproximación mediante
el correspondiente rectángulo.
Z b
Si queremos aproximar la integral f (x) dx con mejor exactitud podemos dividir el
a
intervalo [a, b] en n subintervalos, o sea, considerar la partición del intervalo
donde
b−a
xk = a + k, n = 0, 1, 2, ..., n, x0 = a, xn = b. (8.2.3)
n
Si ahora usamos la aditividad de la integral
Z b Z x1 Z xk+1 Z b
f (x) dx = f (x) dx + · · · + f (x) dx + · · · + f (x) dx. (8.2.4)
a a xk xn−1
Z xk+1
y aplicamos a cada sumando f (x) dx la fórmula (8.2.1)obtenemos la ecuación
xk
b n−1
b−aX
Z
xk + xk+1
f (x) dx = f + R(ξ), (8.2.5)
a n 2
k=0
donde
(b − a)2
|R(ξ)| ≤ M , M = máx |f 00 (x)|.
24n2 x∈[a,b]
152
Veamos como implementar lo anterior con M AXIMA CAS. Definimos el intervalo [a, b],
el número de puntos en que vamos a dividir en intervalo y definimos la partición que
usaremos:
(%i6) define(f(x),x^2);
rec:sum(f((x[k]+x[k+1])/2),k,0,Nu-1)*((b-a)/Nu);
float(%);
(%o6) f(x):=x^2
(%o7) 533/1600
(%o8) 0.333125
En este caso, como la función tiene primitiva, podemos comparar el resultado numérico
con el valor exacto
(%i9) exac:float(integrate(f(x),x,a,b));
float(abs(rec-exac));
(%o9) 0.33333333333333
(%o10) 2.083333333333104*10^-4
n−1
!
b
b−a
Z X
f (x) dx = f (a) + f (b) + 2 f (xk ) + R(ξ), (8.2.7)
a 2n
k=1
R. Álvarez Nodarse Introducción a M AXIMA CAS 153
y y
f(x) f(x)
x x
Figura 8.4: Aproximación de una integral por el método de los trapecios. A la izquierda
vemos el área bajo la curva que queremos calcular. A la derecha, la aproximación mediante
el correspondiente trapecio.
donde
(b − a)2
|R(ξ)| ≤ M , M = máx |f 00 (x)|.
12n2 x∈[a,b]
(%i11) kill(all)$
a:0;b:1;x[0]:a;Nu:20; x[n]:=x[0]+n*(b-a)/Nu;
(%o1) 0
(%o2) 1
(%o3) 0
(%o4) 20
(%o5) x[n]:=x[0]+(n*(b-a))/Nu
(%i6) define(f(x),x^2);
tra: (f(a)+f(b)+ 2*sum(f(x[k]),k,1,Nu-1))*((b-a)/(2*Nu))$
float(%);
(%o6) f(x):=x^2
(%o8) 0.33375
(%i9) exac:float(integrate(f(x),x,a,b));
float(abs(tra-exac));
(%o9) 0.33333333333333
(%o10) 4.166666666666763*10^-4
donde A, B, C son tales que R(ξ) es igual a cero si f (x) = 1, f (x) = x y f (x) = x2 ,
respectivamente. Es decir, si sustituimos en (8.2.8) la función f por cualquiera de las
funciones f (x) = 1, f (x) = x o f (x) = x2 , la fórmula es exacta, o sea R(ξ) = 0. Realizando
dicha sustitución obtenemos un sistema de ecuaciones para las incógnitas A, B, C lo que
nos conduce a la expresión
Z b
b−a 4(b − a) a+b b−a
f (x) dx = f (a) + f + f (b) + R(ξ). (8.2.9)
a 6 6 2 6
Este método es equivalente a aproximar el área debajo de f por una parábola (ver figura
8.5).
y y
f(x) f(x)
x x
Figura 8.5: Aproximación de una integral por el método de Simpson. A la izquierda vemos
el área bajo la curva que queremos calcular. A la derecha, la aproximación usando el
método de los trapecios que equivale a encontrar el área bajo cierta parábola.
Z b
Al igual que en los casos anteriores vamos aproximar la integral f (x) dx con mejor
a
exactitud dividiendo el intervalo [a, b], en este caso, en 2n subintervalos de la forma
[a, b] = [a, x1 ] ∪ [x1 , x2 ] ∪ · · · ∪ [x2n−2 , x2n−1 ] ∪ [x2n−1 , b],
donde
b−a
xk = a + k, k = 0, 1, 2, ..., 2n, x0 = a, x2n = b.
2n
Apliquemos ahora la fórmula de Simpson (8.2.9) en cada subintervalo [x2k , x2k+2 ], k =
0, 1, ..., n − 1, o sea, escribamos la integral original como la suma de las integrales
Z b Z x2 Z x2k+2 Z b
f (x) dx = f (x) dx + · · · + f (x) dx + · · · + f (x) dx.
a a x2k x2n−2
y apliquemos el método de Simpson a cada uno de los sumandos. Nótese que los intervalos
siguen teniendo una longitud x2k+2 − x2k = b−a n igual que antes. Esto nos conduce a la
expresión
n n−1
Z b !
b−a X X
f (x) dx = f (a) + f (b) + 4 f (x2k−1 ) + 2 f (x2k ) + R(ξ), (8.2.10)
a 6n
k=1 k=1
donde
(b − a)5
|R(ξ)| ≤ M , M = máx |f (4) (x)|.
2880n4 x∈[a,b]
Implementemos este método con M AXIMA. Primero definimos los puntos de la parti-
ción
R. Álvarez Nodarse Introducción a M AXIMA CAS 155
(%i11) kill(all)$
(%i1) a:0;b:1;x[0]:a;Nu:10;
x[n]:=x[0]+n*(b-a)/(2*Nu);
(%o1) 0
(%o2) 1
(%o3) 0
(%o4) 10
(%o5) x[n]:=x[0]+(n*(b-a))/(2*Nu)
(%i6) define(f(x),x^2);
simp: (f(a)+f(b)+ 4*sum(f(x[2*k-1]),k,1,Nu)+
2*sum(f(x[2*k]),k,1,Nu-1))*((b-a)/(6*Nu))$
float(%);
(%o6) f(x):=x^2
(%o8) 0.33333333333333
(%i9) exac:float(integrate(f(x),x,a,b));
float(abs(simp-exac));
(%o9) 0.33333333333333
(%o10) 0.0
utilizando las fórmulas (8.2.1), (8.2.6), (8.2.9), respectivamente. Comparar los resultados
con el resultado exacto
Z 1
2 1
cos xdx = sen = 0,4794255386 . . .
0 2
por los métodos de de los rectángulos, los trapecios y de Simpson, respectivamente, utilizando
en todos ellos una partición del intervalo [0, 1] con n = 4 puntos. ¿Quién aproxima mejor?
156
utilizando los métodos de de los rectángulos, los trapecios y de Simpson cuando n = 4. Compa-
rar los resultados con el resultado exacto con 10 cifras decimales I = 0,7468241328... Utiliza
la serie de McLaurin para calcular un valor aproximado y compáralo con los anteriores.
(%o11) kill(all)$
(%i1) f(x):=3*x^2+2*x+1;
integrate(f(x),x,0,1);
(%o1) f(x):=3*x^2+2*x+1
(%o2) 3
Vamos ahora a crear una lista de los valores de las x y su correspondiente lista de sus
imágenes. Para ello tomaremos el intervalo [0, 1] y lo dividiremos en 100 subintervalos
(luego tendremos 101 nodos) pues necesitamos aplicar tanto la fórmula de los rectángulos
como la de Simpson a tres puntos consecutivos xn−1 , xn , xn+1 :
A continuación aplicamos la fórmula de (8.2.5). Para ello hay que distinguir dos casos. El
primero corresponde al caso cuando la función está dada explícitamente y que correspon-
de exactamente a la fórmula (8.2.5). Este caso es el calculado en la variable rec. Para el
segundo caso conviene reescribir (8.2.5) de la siguiente forma
Z b n−1
X xk + xk+1
f (x) dx = f (xk+1 − xk ) + R(ξ), (8.3.1)
a 2
k=0
lo que nos conduce a definir la variable recl que nos calcula el valor aproximado de la
integral usando las listas de los valores de las x y f (x). Aquí conviene recordar que cuando
se trabaja con listas los elementos de las mismas se ordenan comenzando en la posición
uno2 . Así tenemos
(%i13) rec:sum(f(x[2*k-1]),k,1,(nn-1)/2)*(2*h);
recl:sum(lf[2*k]*(lx[2*k+1]-lx[2*k-1]),k,1,nn/2);
recl-rec;
(%o13) 2.999899999999999
(%o14) 2.9999
(%o15) 8.881784197001253*10^-16
Como vemos la diferencia es del orden de precisión de M AXIMA (en este caso 10−16 ) y la
razón está en el uso de float para aproximar numéricamente los valores de la función f y
de las x (recordemos que M AXIMA hace los cálculos simbólicos por defecto). Si eliminamos
los dos comandos float el resultado es la fracción 29999/10000.
Pasemos ahora al caso de la fórmula de los trapecios. Aquí podemos tomar cualquier
partición pero por coherencia y para compararlo con los otros dos tomaremos la mismas
listas que antes y modificaremos la expresión (8.2.7) de forma análoga a (8.3.1):
(%i21) simpl:sum((1/6)*(lx[2*k+1]-lx[2*k-1])*(lf[2*k-1]+4*lf[2*k]+
lf[2*k+1]), k,1,(nn)/2);
simp:float((f(lx[1])+f(lx[nn])+2*sum(f(lx[2*k+1]),k,1,(nn-2)/2)
+4*sum(f(lx[2*k]),k,1,(nn)/2))*(h/3));
2
Por ejemplo si hacemos lx[1]; obtenemos el valor 0, pero si escribimos lx[0]; obtenemos el mensaje de
error: apply: no such "list.element: [0] aunque el valor de x[0] está bien definido.
158
simpl-simp;
(%o19) 2.999999999999999
(%o20) 2.999999999999999
(%o21) 0.0
(%i22) simpl-3;
(%o22) -4.440892098500626*10^-16
Nótese que debido a que hemos usado float el resultado que obtenemos no es 3, pero
la diferencia es del orden de precisión con que estamos trabajando. Si usamos valores
exactos el resultado es 3 como cabría esperar:
(%i22) kill(all)$
(%i1) a:0$ b:1$ Nu:100$
h:((b-a)/(Nu))$
x[0]:a; x[n]:=x[0]+n*h;f(x):=3*x^2+2*x+1;
lx:makelist( x[k],k,0,Nu)$ length(lx);
lf:makelist((f(x[k])),k,0,Nu)$ nn:length(lf);
simpl:sum((1/6)*(lx[2*k+1]-lx[2*k-1])*(lf[2*k-1]+4*lf[2*k]
+lf[2*k+1]), k,1,(nn)/2);
(%o5) 0
(%o6) x[n]:=x[0]+n*h
(%o7) f(x):=3*x^2+2*x+1
(%o9) 101
(%o11) 101
(%o12) 3
Como ejercicio proponemos al lector que construya una tabla de valores para una
función algo más complicada, por ejemplo para f (x) = 2e−x/5 cos (2x + π/3) y repita los
operaciones antes descritas.
(%i13) kill(all)$
(%i1) lis:[0,1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1,0,
1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1,0]$
length(lis);
wxplot2d([discrete,lis])$
(%o2) 41
R. Álvarez Nodarse Introducción a M AXIMA CAS 159
La idea es encontrar los máximos y mínimos locales de la lista. El máximo y mínimo global
se pueden encontrar con las órdenes smax y smin del paquete descriptive
(%i4) load(descriptive)$
(%i5) smax(lis); smin(lis);
(%o5) 5
(%o6) 0
Aquí nos interesan dos cosas: los extremos y su posición. La idea es buscar a lo largo
de la lista el cambio de tendencia (creciente a decreciente y viceversa) asumiendo que si
se repite un valor varias veces, tomaremos como extremo el último de ellos. Como reto
dejamos al lector que modifique la secuencia de forma que nos informe si hay puntos
consecutivos con el mismo valor.
(%i7) comp:length(lis)-2;
l1:makelist( lis[i]>lis[i+1] or lis[i+1]<=lis[i+2] ,i,1,comp)$
l2:makelist( lis[i]<lis[i+1] and lis[i+1]>=lis[i+2] ,i,1,comp)$
(%i10) transpose(matrix(l1,l2));
lis[i]>lis[i+1] or lis[i+1]<=lis[i+2]
tiene como salida true si una de las dos comparaciones es cierta y false únicamente si
ambas son falsas. Por el contrario
tiene como salida true únicamente cuando ambas son ciertas y false en cualquier otro
caso. En general para los operadores lógicos and, not, or se tienen los resultados están-
dar
160
A B A and B A or B not A
true true true true false
true false false true false
false true false true true
false false false false true
Las listas l1 y l2 que hemos construido son complementarias y todos sus elementos son
true y false, respectivamente, excepto en las posiciones donde está el máximo local. Lo
anterior nos permite usar el comando sublist_indices que ya describimos en la página
16 combinado con la función indeterminada lambda para encontrar la posición en la lista
de los máximos locales:
Para encontrar la posición en nuestra la lista original lis sólo tenemos que adicionar 1 a
cada uno de los valores de cualquiera de las salidas anteriores:
y encontramos los valores que toman dichos máximos (en nuestro ejemplo evidentemente
son los valores iguales a 5)
(%i14) makelist(lis[k],k,indi);
(%o14) [5,5,5,5]
Dado que este procedimiento lo usaremos varias veces a lo largo de estas notas vamos a
definir una función que lo haga todo de una vez, lo cual haremos usando la orden block
que ya vimos en la página 55:
o, equivalentemente,
De forma análoga podemos construir la función que encuentre los mínimos locales de una
lista. Dejamos como ejercicio al lector que adapte las secuencias anteriores para el caso de
los mínimos. La función en este caso es:
cuya salida efectivamente nos da la posición de los mínimos locales con la cual podemos
encontrar los valores de los mismos.
(%i20) indimin:lismin(lis);
(%o20) [11,21,31]
(%i21) makelist(lis[k],k,indimin);
(%o21) [0,0,0]
Como vamos usar las funciones lismax y lismin definidas anteriormente varias veces
es conveniente crear nuestro propio paquete que las contenga y al que podemos agregar
luego cuantas funciones necesitemos. Hay dos formas muy sencillas. La primera es sim-
plemente crear un fichero .mac que contengan las dos definiciones y lo guardamos donde
M AXIMA lo pueda encontrar (podemos usar la orden file_search_maxima que ya comen-
tamos en la página 13). La otra forma es escribir en una nueva sesión de WX M AXIMA la
secuencia
Vamos a usar nuestras dos funciones para el cálculo numérico de los extremos de una
función de una variable. Como ejemplo tomaremos la función f : [0, 2π] 7→ R, f (x) =
exp(−x/4) sin(x) + cos(3x) y crearemos las listas de las x y f (x) correspondientes:
(%o22) kill(all)$
(%i1) load(draw)$
f(x):=exp(-x/4)*sin(x)+cos(3*x);
a:0$ b:6*%pi$ Nu:1000; h:float((b-a)/(Nu))$
x[0]:a; x[n]:=x[0]+n*h;
(%o2) f(x):=exp((-x)/4)*sin(x)+cos(3*x)
(%o8) x[n]:=x[0]+n*h
162
A continuación creamos la lista de las x con makelist y el de sus imágenes según f(x)
para lo cual usamos el comando map que ya describimos en la página 51
(%i9) xx:makelist(x[k],k,0,Nu)$
ll:map(f,xx)$
wxdraw2d(point_type=filled_circle, points_joined = true,
point_size = .5, points(xx,ll))$
(%t11) (Graphics)
A continuación cargamos nuestro paquete que contiene las funciones lismax y lismin
usando la orden load:
(%i12) load("proglist.mac");
(%o12) "proglist.mac"
y buscamos los valores donde se alcanzan los máximos así como los valores donde se
alcanzan y cuando valen dichos valores:
(%i13) lma:lismax(ll);
(%o13) [7,110,223,336,445,556,668,779,890]
(%i14) xlma:makelist(xx[k],k,lma);
(%o14) [0.1130973355292325, 2.054601595447725, ... , 16.75725521424795]
(%i15) ylma:makelist(ll[k],k,lma);
(%o15) [1.052700670327255, 1.522523160830247, ... , 0.9868383461695104]
(%i16) pmax:makelist([xx[k],ll[k]],k,lma);
(%o16) [[0.1130973355292325,1.052700670327255],...,
[16.75725521424795,0.9868383461695104]]
1.053
1.5
1.0525
1
1.052
0.5
1.0515
Y
Y
0
1.051
-0.5
1.0505
-1 1.05
-1.5 1.0495
0 2 4 6 8 10 12 14 16 18 0.095 0.1 0.105 0.11 0.115 0.12 0.125 0.13
X X
Figura 8.6: Los máximos de la función f (x) = exp(−x/4) sin(x) + cos(3x) calculados
numéricamente (izquierda) y detalle del primer máximo (derecha).
Podemos también mostrar una tabla con las salidas alrededor de cada extremo
(%i22) transpose(matrix(makelist(
makelist(ll[k],k,lma[i]-1,lma[i]+1), i,1,length(lma))));
(%o22) matrix([[1.052210542969385,1.052700670327255,1.049968020465215]],
[[1.521882481561259,1.522523160830247,1.519862713256897]],
.
.
.
[[1.021469901618179,1.022013705837951,1.019355791634181]],
[[0.9856783052939371,0.9868383461695104,0.9848072691935124]])
Como ejercicio proponemos al lector que adapte el ejemplo anterior para encontrar los
mínimos de la función y luego hacer las correspondientes comprobaciones. Para ello se
recomienda usar la función lismin definida en la página 161.
Vamos a considerar ahora el siguiente problema. Supongamos que tenemos una lista
de datos que representa cierta medida experimental (por ejemplo la velocidad de cier-
ta partícula) y queremos encontrar: sus extremos locales y la variación media de dicha
medida.
Para generar la correspondiente lista usaremos una función relativamente sencilla que
nos permita obtener los resultados analíticos “exactos” de forma que podamos comprobar
el algoritmo. Como función test tomaremos la función f (x) = x/100 + sin(x/2) definida
en el intervalo [0, 100]. Lo primero que haremos es generar una lista de valores de f :
164
(%i25) kill(all)$
(%i2) load(draw)$ load("proglist.mac");
(%o2) "proglist.mac"
(%i3) define(f(x),x/100+sin(1/2*x));
(%o3) f(x):=x/100+sin(x/2)
(%i4) a:0$ b:100$ Nu:1000$ h:(b-a)/(Nu)$
x[0]:a$ x[n]:=x[0]+n*h;
(%o9) x[n]:=x[0]+n*h
(%i12) xx:makelist(x[n],n,0,Nu)$
ff:makelist(f(n),n,xx)$
draw2d(point_type=filled_circle, points_joined = true,
point_size = 1, points(xx,ff), yrange=[-1,2],
xaxis =true, xaxis_type=solid,grid = true)$
(%t12) (Graphics)
(%i16) indimax:lismax(ff);
listamax:makelist(xx[k],k,%)$ float(%);
listama:f(listamax)$
(%o13) [33,158,284,410,535,661,787,912]
(%o15) [3.2,15.7,28.3,40.9,53.4,66.0,78.6,91.1]
(%i20) indimin:lismin(ff);
listamix:makelist(xx[k],k,%)$ float(%);
listami:f(%)$
(%o17) [95,221,346,472,598,723,849,974]
(%o19) [9.4,22.0,34.5,47.1,59.7,72.2,84.8,97.3]
y los dibujamos para comprobar que el cálculo ha sido correcto (ver la gráfica derecha de
la figura 8.7):
Calculemos ahora los extremos de forma exacta usando las técnicas habituales del
cálculo diferencial. Primero calculamos la primera derivada de f y la representamos
(%i22) define(df(x),diff(f(x),x));
(%o22) df(x):=cos(x/2)/2+1/100
(%i23) wxdraw2d( explicit(df(x),x,0,100), yrange=[-.6,.6],
xaxis =true, xaxis_type=solid, grid=true)$
(%t23) (Graphics)
R. Álvarez Nodarse Introducción a M AXIMA CAS 165
2 2
1.5 1.5
1 1
0.5 0.5
Y
Y
0 0
-0.5 -0.5
-1 -1
0 20 40 60 80 100 0 20 40 60 80 100
X X
Figura 8.7: La función f (x) = x/100 + sin(x/2) (izquierda) y sus extremos (derecha)
calculados a partir de la lista de sus valores.
0.6 2
0.4 1.5
0.2 1
0 0.5
Y
-0.2 0
-0.4 -0.5
-0.6 -1
0 20 40 60 80 100 0 20 40 60 80 100
X X
Figura 8.8: La función f 0 (x) = 1/100 + 1/2 cos(x/2) (izquierda) y los máximos locales
exactos (derecha) de f (x) = x/100 + sin(x/2).
Para calcular los ceros usamos el comando find_root (dejamos como ejercicio que
el lector construya la lista de los valores exactos usando el comando solve y las propie-
dades de las funciones trigonométricas). Para ello necesitamos saber entre que valores
aproximadamente se encuentran los ceros de f 0 (x).
Un vistazo a la gráfica 8.8 (izquierda) nos indica que los ceros son cercanos a los de la
función3 cos x/2) por lo que crearemos una lista con dichos valores y luego en el entorno
de cada uno de ellos buscamos los ceros que guardaremos en la lista extremos
(%i25) cc:makelist(float((2*k+1)*%pi),k,0,15)$
nex:length(%);
(%o25) 16
(%i26) for k:1 thru nex do
extre[k]:find_root(df(x)=0,x,cc[k]-0.2,cc[k]+.2)$
(%i27) extremos:makelist(extre[k],k,1,nex);
(%o27) [3.181595320736574, 9.3847752936226, ... ,97.3493695941368]
Comprobamos que efectivamente son extremos locales evaluando los valores de la segun-
da derivada:
3
Por ejemplo, ejecútese la orden plot2d([cos(x/2)/2+1/100,cos(x/2)], [x,0,20]) .
166
(%i28) define(d2f(x),diff(f(x),x,2));
(%o28) d2f(x):=-sin(x/2)/4
(%i30) val2d:d2f(extremos); length(%);
(%o29) [-0.2499499949989997,0.2499499949989997, ... ,0.2499499949989997]
(%o30) 16
Así tenemos máximo, mínimo, máximo, etc. Vamos ahora a generar la lista de los máximos
y compararla con la que obtuvimos antes. Para ello usaremos el comando is cuya sintaxis
es is(predicado) que lo que hace es intentar evaluar el predicado dando como salida
true, false o unknown. Lo que haremos pues es determinar si la segunda derivada es
negativa, lo cual ocurre si la salida es true, e implica que en dicho punto se alcanza un
máximo relativo. En caso contrario, si la salida es false, habrá un mínimo4
(%i32) sig:makelist(is(val2d[i]<0),i,1,nex);length(%);
(%o31) [true,false,true,false,true,false,true,false,true,false,
true,false,true,false,true,false]
(%o32) 16
(%i33) posmax:sublist_indices (sig, lambda ([x], x='true));
(%o33) [1,3,5,7,9,11,13,15]
(%i37) maxex-listamax;
(%o37) [-0.01840467926342581,0.04796593509574798,...,0.04618962125078951]
cuyo posible error es menor que 0.1, siendo este el paso que usamos para crear la lista
original.
Como ejercicio dejamos al lector que realice los cálculos para los mínimos locales.
Pasemos ahora a calcular la media de nuestra magnitud en cierto intervalo [a, b]. Para
ellos usaremos la fórmula5 Z b
f := f (x)dx. (8.4.1)
a
4
Aquí, en general, conviene tener cuidado con el posible valor cero, donde sabemos que el criterio de la
segunda derivada no es concluyente.
5 1
Rb
También podríamos tomar el valor f := b−a a
f (x)dx.
R. Álvarez Nodarse Introducción a M AXIMA CAS 167
Dado que estamos suponiendo que nuestros datos son una lista con los valores de xn y
f (xn ) vamos a usar el método de Simpson para calcular la integral (ver el apartado 8.3,
página 156). Ahora bien, como ya vimos allí nuestra lista ha de tener un número impar
de elementos por lo que lo que primero haremos es definir una función que dada una
lista nos de como salida la misma lista si el número de elementos es impar, y si es par
que elimine, digamos el último. Para ello usaremos el comando evenp(num) cuya salida es
true si el número num es par y false en otro caso. Ello lo combinaremos con el comando
rest(lista,-1) que ya comentamos en la sección 2.2 que elimina el último elemento de
la lista. Para no repetir la operación con la lista de las x y las f (x) usaremos la orden
block. Así definiremos la función limpar de la siguiente forma:
Como ejercicio definir una función que genere, a partir de una lista cualquiera dada,
una lista con un número impar eliminando el último elemento en caso de que la lista
original tenga un número par de elementos (la respuesta es la orden limparuna del fichero
proglist.mac).
Vamos ahora a construir una función que calcule la media. Para ello usaremos el mé-
todo de Simpson (ver página 157) para aproximar la fórmula (8.4.1). La entrada estará
constituida por las listas t y p que corresponden a los valores de las x ∈ [a, b] y sus corres-
pondientes imágenes de f (x). Es conveniente usar nuevamente el comando block
Nótese que las listas t y p deben tener el mismo número de puntos que ha de ser impar.
Un ejercicio interesante para el lector es adaptar el comando anterior para que siempre
use la fórmula de Simpson con listas de tamaño impar6 y que además genere un aviso
cuando cambie la lista. Conviene incluir el comando resultante de este ejercicio en nuestro
paquete proglist.mac con el nombre cmedia ya que lo usaremos más adelante.7
Como vamos a utilizar estas funciones en otras sesiones conviene agregarlas a nuestro
paquete proglist.mac. La pregunta que surge a continuación es qué intervalo tomar para
calcular la media. Es evidente que nuestra función no es periódica pero tiene un compor-
tamiento oscilante así que vamos a elegir como intervalo [a, b] el intervalo entre los dos
primeros máximos.
0.5
Y
0
-0.5
4 6 8 10 12 14
X
Figura 8.9: La función f (x) = x/100 + sin(x/2) representada entro sus dos primeros
máximos.
Como las listas tienen un número par de elementos hay que eliminar uno de los ele-
mentos. Así que usamos la orden limpar que definimos antes
(%i46) limpar(xxx,fff)$
xn:limpar(xxx,fff)[1]$ length(xn);
fn:limpar(xxx,fff)[2]$ length(fn);
(%o48) 125
(%o50) 125
Finalmente calculamos los valores de la media usando los valores numéricos con la orden
cmedio y lo comparamos con el valor exacto integrando nuestra función
(%i51) medsimp:float(cmedio(xn,fn));
(%o51) 0.08058791197546415
(%i53) integrate(f(x),x,xxx[1],xxx[length(xxx)])$
medex:float(%)/(xxx[length(xxx)]-xxx[1]);
(%o53) 0.08919101667914105
(%i54) abs(medsimp-medex);
(%o54) 0.008603104703676895
Como ejercicio dejamos al lector que calcule la media cuando tomamos como intervalos
los puntos correspondientes al primer y cuarto máximos, respectivamente. ¿Qué ocurre
si tomamos todo el intervalo, o distintos intervalos de longitud arbitraria? ¿Tiene sentido
hacer esto último?
di
L + Ri = U (t),
dt
(%i55) kill(all)$
(%i1) lru:L*'diff(i,t)+R*i-U=0;
(%o1) -U+i*R+('diff(i,t,1))*L=0
(%i2) ode2(lru,i,t);
(%o2) i=%e^(-(t*R)/L)*((%e^((t*R)/L)*U)/R+%c)
(%i3) ic1(%,t=0,i=0);
(%o3) i=(%e^(-(t*R)/L)*(%e^((t*R)/L)-1)*U)/R
(%i4) define(i(L,R,U,t),second(%));
(%o4) i(L,R,U,t):=(%e^(-(t*R)/L)*(%e^((t*R)/L)-1)*U)/R
(%i5) wxplot2d( i(1,1,3,t), [t,0,10], [xlabel,"t"], [ylabel,"i(t)"])$
El segundo caso se deja como ejercicio, así como exportar ambos gráficos en formato pdf
y jpg.
0.8
3
0.6
2.5
0.4
2
0.2
i(t)
i(t)
1.5
0
1 -0.2
0.5 -0.4
0 -0.6
0 2 4 6 8 10 0 2 4 6 8 10
t t
di
Figura 8.10: La intensidad i(t) para EDO L dt + Ri = U (t), con U = U0 (izquierda) y
U0 sen(ωt) (derecha).
Problema 8.5.0.1 Sea una esfera hueca homogénea de radio interior r1 y radio exterior r2 .
Supongamos que la temperatura de la cara interior es T1 y la exterior es T2 . Encontrar la
dT
temperatura en la esfera en función del radio si T satisface la EDO Q = −κr2 ,κ>0y
dr
dibujar T (r).
170
11111111111111111111111
00000000000000000000000
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
T1 1111
0000
00000000000000000000000
11111111111111111111111
0000
1111
00000000000000000000000
11111111111111111111111
0000
1111
00000000000000000000000
11111111111111111111111
r1
0000
1111
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000
11111111
r2
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000
11111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
00000000000000000000000
11111111111111111111111
T2
(%i1) kill(all)$
assume(vf*w>1,g>0,k>0,w>0);
(%o1) [vf*w>1,g>0,k>0,w>0]
(%i2) vel:'diff(v,t) = g*(1- w^2*v^2) ;
(%o2) 'diff(v,t,1)=g*(1-v^2*w^2)
(%i3) sol:ode2(vel,v,t);
(%o3) (log(v*w+1)-log(v*w-1))/(2*g*w)=t+%c
R. Álvarez Nodarse Introducción a M AXIMA CAS 171
(%i4) logcontract(%);
ic1(%,t=0,v=v0);
solve(%,v);
(%o4) -log((v*w-1)/(v*w+1))/(2*g*w)=t+%c
(%o5) -log((v*w-1)/(v*w+1))/(2*g*w)=-(log((v0*w-1)/(v0*w+1))-2*g*t*w)/(2*g*w)
(%o6) [v=((v0*w+1)*%e^(2*g*t*w)+v0*w-1)/((v0*w^2+w)*%e^(2*g*t*w)-v0*w^2+w)]
Finalmente, definimos una función que usaremos más adelante y calculamos el límite
asintótico cuando t → ∞
(%i7) define(solcaso2(v0,w,g,t),rhs(%[1]))$
(%i8) limit( solcaso2(v0,w,g,t),t,inf);
(%o8) 1/w
(%i9) load(diffeq);
(%o9) "/usr/share/maxima/5.36.1/share/numeric/diffeq.mac"
(%i10) kill(k,g,w)$
k:1$ g:9.8$ w:sqrt(k/g)$ x0:0$ x1:3$
f(x,y):= g*(1- w^2*y^2); h:1/20$
(%o16) f(x,y):=g*(1-w^2*y^2)
(%i18) solnum:runge1(f,0,3,h,1)$
(%i19) wxplot2d([[discrete,solnum[1],solnum[2]],solcaso2(1,w,g,x),1/w],
[x,0,3], [xlabel,"t"],[ylabel,"v(t)"],[y,1,3.75],
[legend,"solución numérica","Solución exacta","solución asintótica"]);
(%t20) (Graphics)
Problema 8.5.0.4 Resolver los otros dos casos analíticamente y numéricamente y comparar
los resultados.
Imaginemos que tenemos una población de cierta especie (consideraremos que tene-
mos un número bastante alto de individuos) y sea p(t) el número de individuos de dicha
especie en el momento t (evidentemente p(t) ∈ N). Sea r(t, p) la diferencia entre en índice
de natalidad y mortalidad de la población. Supongamos que la población esta aislada (o
sea, no hay emigración ni inmigración). Entonces la variación p(t + h) − p(t) es proporcio-
nal a p(t)h y el coeficiente de proporcionalidad es r(t, p). Luego, tomando el límite h → 0,
obtenemos la EDO
p(t + h) − p(t) = r(t, p)p(t)h, h → 0, ⇒ p0 (t) = r(t, p)p(t).
172
4 5
solución numérica r=1.7
Solución exacta 4.5 r=2
3.5 solución asintótica r=3
4
3
3.5
v(t), r=2
v(t)
2.5 3
2.5
2
2
1.5
1.5
1 1
0 0.5 1 1.5 2 2.5 3 0 0.5 1 1.5 2 2.5 3
t t
Figura 8.11: Caída de un cuerpo viscoso descrito por la EDO (8.5.1) con r = 2 (izquierda)
y comparación de las soluciones para r = 1,7, 2, 3 (derecha).
El modelo anterior se conoce como modelo de Malthus o modelo malthusiano pues fue
propuesto por el economista inglés Thomas R. Malthus (1766–1834). La solución de
(8.6.1) es una exponencial
pm (t) = p0 er(t−t0 ) . (8.6.2)
Está claro que si r < 0 la especie esta condenada a la extinción y si r > 0 ésta crece en
proporción geométrica.
Vamos a analizar este modelo con ayuda de M AXIMA. Para ello resolvemos la ecuación
diferencial
(%i10) kill(all)$
(%i1) kill(p,r)$
edo:'diff(p,t,1) = r*p;
sol:ode2(edo,p,t);
solmal:expand(ic1(sol,t=t0,p=p0));
(%o2) 'diff(p,t,1)=p*r
(%o3) p=%c*%e^(r*t)
(%o4) p=p0*%e^(r*t-r*t0)
(%i5) define(maltus(t,t0,p0,r),second(solmal));
Veamos un ejemplo. Según datos recopilados por la Oficina del Censo de los Estados
Unidos (http://www.census.gov/population/international/data/) la población mun-
dial en 1950 era de 2,558·109 personas. Vamos a usar los datos de dicha organización para,
R. Álvarez Nodarse Introducción a M AXIMA CAS 173
Vamos ahora a hacer una regresión no lineal para estimar el valor de r en la fórmula de
Maltus
Como vemos nos da un error. El ajuste no converge. Para intentar resolver el problemas
echaremos mano de un pequeño truco: cambiar los valores de p por sus logaritmos, de
forma que la fórmula a ajustar es ahora log(p) = log(p0 ) + r(t − t0 ).
(%i18) xx1:makelist(xx[k][1],k,1,length(xx))$
yylog1:makelist(float(log(yy[k][1])),k,1,length(yy))$
datalog:transpose(float(matrix(xx1,yylog1)))$
logpp0:yylog1[1];
(%o21) 21.66234635911915
(%i22) kill(t,p,r)$
mse : lsquares_mse (datalog, [t, logp], logp=logpp0+r*(t-1950))$
sol:lsquares_estimates_approximate(mse, [r]);
rr:second(sol[1][1]);
*************************************************
N= 1 NUMBER OF CORRECTIONS=25
INITIAL VALUES
F= 1.328767598368111D+03 GNORM= 2.704354242998442D+03
*************************************************
I NFN FUNC GNORM STEPLENGTH
1 2 4.133553696694144D-01 4.764575700155741D+01 3.697740422095198D-04
2 3 9.065760190767720D-04 9.401026965441327D-15 1.000000000000000D+00
THE MINIMIZATION TERMINATED WITHOUT DETECTING ERRORS.
IFLAG = 0
(%o24) [[r=0.01731313844533347]]
(%o25) 0.01731313844533347
que esta vez funciona sin problemas. A continuación definimos la función de ajuste y la
dibujamos (ver gráfica de la izquierda de la figura 8.12)
(%i26) funfit(t):=logpp0+rr*(t-1950);
(%o26) funfit(t):=logpp0+rr*(t-1950)
(%i27) plot2d([[discrete,xx1,yylog1],funfit(t)],[t,1950,2015],[y,21.6,23],
[style,points,[lines,3]],
[legend,"log(No personas)","Estimación maltusiana"]);
(%t27) << Graphics >>
Si este coeficiente está próximo a uno entonces tendremos una ajuste bueno, de hecho
mientras más cercano a uno sea Ccorr mejor será el ajuste.
Finalmente recuperamos los valores reales y dibujamos los resultados (ver gráfica de la
derecha de la figura 8.12)
(%i31) yy2:makelist(float((yy[k][1])),k,1,length(yy))$
(%i32) maltus(t,1950,pp0,rr);
(%o32) 2.557628654*10^9*%e^(0.01731313844533347*t-33.76061996840027)
R. Álvarez Nodarse Introducción a M AXIMA CAS 175
(%i33) SSE:sum(float((yy2[k]-maltus((xx1[k]),1950,pp0,rr))^2),
k,1,length(xx1))$
SST:sum( (yy2[k]-mean(yy2))^2 , k,1,length(yy1))$
corre:sqrt(1-SSE/SST);
(%o35) 0.9920141011306452
(%i36) wxplot2d([[discrete,xx1,yy2],maltus(t,1950,pp0,rr)],[t,1950,2015],
[style,points,[lines,3]],
[legend,"No personas","Estimación maltusiana"]);
(%t36) << Graphics >>
23 8x109
log(Nº personas: datos) Nº personas: datos
22.8 Estimación maltusiana 7x109 Estimación maltusiana
22.6
6x109
22.4
5x109
22.2
4x109
22
21.8 3x109
21.6 2x109
1950 1960 1970 1980 1990 2000 2010 1950 1960 1970 1980 1990 2000 2010
t t
De la gráfica se ve claramente que para t > 2000 empieza a existir una divergencia
clara entre la predicción maltusiana y la real. Podemos calcular algunos valores
(%i37) maltus(2000,1950,pp0,rr);
(%o37) 6.078375327752732*10^9
(%i38) maltus(2010,1950,pp0,rr);
(%o38) 7.22732389676767*10^9
(%i39) maltus(2025,1950,pp0,rr);
(%o39) 9.370494836416982*10^9
(%i40) maltus(2050,1950,pp0,rr);
(%o40) 1.4445664958926*10^10
Como se puede ver el valor del año 2000 es bastante bueno en comparación con la esti-
mación real de 6,088571383 · 109 , pero ya la predicción del año 2010 empieza a alejarse en
relación a la estimada 6,866332358 · 109 . Nótese que la fórmula de Maltus p(t) = p0 er(t−t0 )
predice que la población se duplica cada
¿Es realista este modelo? Esta claro que no. Por ejemplo, si asumimos que el crecimiento
es según la fórmula de Malthus con los valores que hemos obtenido tendremos que en el
2500 habrán unas 3,5 · 1013 personas. Si tenemos en cuenta que la superficie de la Tierra
176
es de aproximadamente 5,1 · 1014 m2 de las cuales sólo el 30 % es tierra, nos queda que en
ese año la densidad de población será de un habitante por cada 4,2m2 o sea !un cuadrado
de 2m de lado!8
Aunque hemos visto que el modelo funciona razonablemente bien para poblaciones
grandes, hay que hacer varias correcciones pues si p(t) empieza a crecer demasiado habrá
muchos otros factores como la falta de espacio o de alimentos que frenará el crecimiento.
Así que unos años después, en 1837, el matemático y biólogo holandés P. F. Verhulst
propuso un modelo algo más realista conocido como el modelo logístico. Verhulst razonó
que como estadísticamente el encuentro de dos individuos es proporcional a p2 (¿por
qué?) entonces tendremos que sustraerle al término rp un término cp2 , de forma que la
EDO que modeliza una población será
En general c ha de ser mucho más pequeño que r ya que si r no es muy grande la EDO
(8.6.1) es una aproximación bastante buena, pero si p comienza a crecer demasiado en-
tonces el término −cp2 no se puede obviar y termina frenando el crecimiento exponencial.
La EDO (8.6.3) se puede resolver fácilmente pues es una ecuación separable. Para hacerlo
con M AXIMA se requiere un pequeño truco:
(%i46) kill(p,r,c)$
edo:'diff(p,t,1) = p*(r-c*p);
sol:ode2(edo,p,t);
(%o47) 'diff(p,t,1)=p*(r-c*p)
(%o48) -(log(c*p-r)-log(p))/r=t+%c
(%i49) expand(ic1(sol,t=0,p=p0));
logcontract(%);
solexp:solve([%], [p]);
(%o49) log(p)/r-log(c*p-r)/r=-t0+t-log(c*p0-r)/r+log(p0)/r
(%o50) log(-p/(r-c*p))/r=-(r*t0-r*t+log(-(r-c*p0)/p0))/r
(%o51) [p=(p0*r*%e^(r*t-r*t0))/(c*p0*(%e^(r*t-r*t0)-1)+r)]
Así, su solución es
Nótese que lı́mt→∞ p(t) = r/c, independientemente de p0 . En el caso cuando 0 < p0 < r/c
la evolución de la población está representada en la gráfica de la izquierda de la figura
8.13.
Ya estamos en condiciones de definir la función pl (t) (8.6.4) con M AXIMA
8
Malthus abusando de su ecuación predijo un colapso socioeconómico pues proclamó que la capacidad
procreadora de los humanos es tan grande que siempre nacen más niños que los que pueden sobrevivir, lo
cual se agrava por el hecho de que la cantidad de alimentos no crece exponencialmente —Malthus creía que
este crecimiento era aritmético—. Así, Malthus concluyó que un gran número de humanos está predestinado
a sucumbir en la lucha por la existencia. Aunque hoy día no se consideran ciertas las teorías malthusianas,
en su momento tuvieron gran influencia, de hecho fue la lectura del ensayo “Acerca de los fundamentos de la
población” la que indujo a Darwin el mecanismo de selección natural universalmente aceptado hoy día.
R. Álvarez Nodarse Introducción a M AXIMA CAS 177
50 pm(t)
p pl(t)
r/c
40
r/c
30
p(t)
p0 20
10
0
0 20 40 60 80 100
t
t0 t
Figura 8.13: Evolución de la población según el modelo logístico pl (t) (8.6.3) (izquierda)
y su comparación con el modelo malthusiano pm (t) (derecha).
(%i52) define(pob(t,t0,p0,r,c),second(solexp[1]));
(%o52) pob(t,t0,p0,r,c):=(p0*r*%e^(r*t-r*t0))/(c*p0*(%e^(r*t-r*t0)-1)+r)
(%o53) wxplot2d([maltus(t,0,1,0.1),pob(t,0,1,0.1,0.0025),.1/0.0025],
[t,0,100],[y,0,55],[ylabel,"p(t)"],grid2d,
[legend,"pm(t)","pl(t)","r/c"],[style,[lines,3]],
[color,blue,red,black],[box, false],[axes, solid]);
p(t + 1) − p(t)
p0 (t) ≈ = r − cp(t).
p(t)
(%i62) ee:rr/cc;
(%o62) 2.070657561024615*10^11
(%i63) tfin:1950+1/rr*log(ee/pp0);
(%o63) 2203.793146566312
(%i64) maltus(tfin,1950,pp0,rr);
(%o64) 2.070657561024626*10^11
Una gráfica ilustra muy bien lo que ocurre (véase la gráfica de la derecha en la figura
8.14).
(%i65) plot2d([pob(t,1950,pp0,rr,cc),maltus(t,1950,pp0,rr),ee ],
[t,1950,2300],[style,[lines,3]], [legend,"Estimación logística",
"Estimación malthusiana","valor estable"]);
(%t65) << Graphics >>
1.2x1012
8x109 No. personas: datos modelo logistico
modelo logistico modelo malthusiano
1x1012 valor de equilibrio
modelo malthusiano
7x109
8x1011
6x109
6x1011
5x109
4x1011
4x109
2x1011
3x109
0
1950 1960 1970 1980 1990 2000 2010 1950 2000 2050 2100 2150 2200 2250 2300
t
t
Figura 8.14: Comparación de los modelos logístico pl (t) (8.6.4) y malthusiano pm (t)
(8.6.2) (izquierda) y predicción de ambos modelos (derecha).
Obviamente el modelo logístico sigue siendo muy simple ya que no tiene en cuenta ni
las guerras (habituales desde hace cientos de años), ni las epidemias, hambrunas, etc.
R. Álvarez Nodarse Introducción a M AXIMA CAS 179
donde K es la capacidad de carga del medio, que no es más que el tamaño máximo de
población que el medio puede soportar indefinidamente en un periodo determinado (se
puede comprobar que lı́mt→∞ p(t) = K). Obviamente el caso más sencillo es cuando la
capacidad de carga K es constante, no obstante puede darse el caso que dicha capacidad
varíe cíclicamente, de forma que tengamos la ecuación
0 p(t)
p (t) = r p(t) 1 − , p(t0 ) = p0 , r, K0 , K1 > 0.
K0 + K1 cos(ωt + φ)
Comenzamos analizando el caso del modelo logístico puro que ya discutimos en el apar-
tado anterior, para lo que fijamos a = 0 (ver la ecuación (8.6.3))
A partir de la salida de rk creamos las listas de las abscisas y las ordenadas y las dibujamos:
(%i8) pp0:makelist(solnum0[k][2],k,1,length(solnum0))$
tt0:makelist(solnum0[k][1],k,1,length(solnum0))$
wxdraw2d(point_type=filled_circle, points_joined = true,
xlabel = "t", ylabel = "p(t)", yrange=[0.45,1.1],
point_size = 0.5, points(tt0,pp0))$
(%t11) (Graphics)
Como nos interesará lo que pasa para tiempos largos vamos a quedarnos con la segunda
mitad de la lista —la linea roja en la gráfica 8.15 (izquierda)—
9
Ver el artículo Models for single populations. Theoretical Ecology: Principles and Applications, Blackwell
Scientific Publications, 1976, Robert M. May (Eds.), pp. 5-29.
180
(%i12) cola0:floor(length(solnum0)*.5);
colapp0:rest(pp0,cola0)$
colatt0:rest(tt0,cola0)$
wxdraw2d(point_type=filled_circle, points_joined=true,
xlabel = "t", ylabel = "p(t)", yrange=[0.45,1.1],
point_size = 1, points(tt0,pp0),
color=red,points(colatt0,colapp0))$
(%o12) 250
(%t15) (Graphics)
(%i17) solnum:rk(g(t,p),p,p0,[t,0.0,50,h])$
que nos permite representar la solución del modelo fluctuante (azul) y compararla a la
del modelo logístico puro (rojo) —ver gráfica 8.15 (derecha)— para todo el intervalo
—en este caso [0, 50]—
(%i21) pp:makelist(solnum[k][2],k,1,length(solnum))$
tt:makelist(solnum[k][1],k,1,length(solnum))$
wxdraw2d(point_type=filled_circle, points_joined = true,
xlabel = "t", ylabel = "p(t)", yrange=[0.45,1.3],
point_size = 1, points( tt,pp), color=red,
points( tt0,pp0))$
(%t24) (Graphics)
o, si así lo preferimos, para tiempos largos, por ejemplo, a partir de la mitad del tiempo
total escogido –en este caso de [25, 50]— y cuya gráfica la podemos ver en la figura 8.16
(izquierda)
(%i25) cola:floor(length(solnum)*.5);
colapp:rest(pp,cola)$
colatt:rest(tt,cola)$
wxdraw2d(point_type=filled_circle, points_joined=true,
point_size = 1, points(colatt,colapp), color=red,
points(colatt0,colapp0),xlabel="t",ylabel="p(t)")$
(%t28) (Graphics)
Está claro que la solución oscila alrededor del y = 1. Vamos ahora a encontrar donde
tiene sus máximos. Dado que es una lista usaremos los comandos que construimos en el
apartado 8.4. Lo primero que tenemos que hacer es cargar el paquete10 proglist.mac
10
Recuérdese que M AXIMA debe saber donde buscar por lo que quizá haya que especificarle el camino
(path) usando, como ya vimos en la página 13, la opción (Add to path) en la pestaña “Maxima” del menú de
WX M AXIMA .
R. Álvarez Nodarse Introducción a M AXIMA CAS 181
1.1
fluctuación
1.4
1 logístico
0.9 1.2
0.8 1
p(t)
p(t)
0.7
0.8
0.6
0.6
0.5
0 10 20 30 40 50 0 10 20 30 40 50
t t
Figura 8.15: Gráfica de la solución del modelo logístico descrito por la ecuación (8.6.5)
cuando a = 0 (izquierda) y modelo de poblaciones fluctuantes de May descrito por (8.6.2).
(%i31) indimax:lismax(colapp);
mt:makelist(colatt[k],k,indimax);
mp:makelist(colapp[k],k,indimax);
(%o31) [11,74,137,200]
(%o32) [26.0,32.3,38.6,44.9]
(%o33) [1.245676086805322,1.245849815973797,
1.245935016172712,1.245931228967183]
1.4 1.5
fluctuación fluctuación
1.3 logístico 1.4 logístico
1.3 máximos
1.2
1.2
1.1
1.1
p(t)
p(t)
1
1
0.9
0.9
0.8 0.8
0.7 0.7
0.6 0.6
25 30 35 40 45 50 25 30 35 40 45 50
t t
Figura 8.16: Gráfica de la solución asintótica (tiempos grandes) del modelo de poblaciones
fluctuantes de May descrito por (8.6.2) (derecha) y posición de los máximos (derecha).
Finalmente con la orden cmedia que definimos en el ejercicio de la página 167 encontra-
mos el promedio de la solución en un periodo:
(%i40) m1:cmedia(tie,pob);
(%t40) "Longitud de la lista par, eliminando el último elemento"
(%o40) 0.9538472231637653
También se pueden usar las órdenes limparuna o limpar que comentamos en la página
167.
Como ejercicio final repetir el estudio para otros parámetros, por ejemplo, a = 0,4, y
φ = π/6 y compararlos con el caso aquí considerado.
Antes de terminar este apartado conviene mencionar uno de los modelos más simples
de crecimiento de poblaciones cuando intervienen dos especies, una presa y un depre-
dador, conocido como modelo de Lotka-Volterra. Si denotamos por N (t) el número de
individuos (presas) y por P (t) en número de depredadores, el modelo de Lotka-Volterra
está definido por el siguiente sistema no lineal acoplado
dN dP
= N (a − bP ), = P (cN − d), a, b, c, d > 0, N (t0 ) = N0 , P (t0 ) = P0 .
dt dt
Este sistema es, esencialmente, el mismo que el sistema (6.3.1) discutido en el apartado
6.2 así que remitimos al lector a la discusión allí expuesta.
R. Álvarez Nodarse Introducción a M AXIMA CAS 183
(%i1) f(x):=(x-float(%e))*(x-float(%pi))*(x-2.0*float(%gamma));
(%o1) f(x):=(x-float(%e))*(x-float(%pi))*(x-2.0*float(%gamma))
(%i4) xx:makelist(float(k/200.0),k,0,800)$
yy:f(xx)$
lon:length(yy);
(lon) 801
(%i5) wxplot2d([[discrete,xx,yy],f(x)],[x,0,4],
[xlabel,"t"],[ylabel,"y(t)"],[style,points,[lines,3]],
[point_type,diamond],[legend,"lista","funcion"]);
(%t5) (Graphics)
Lo que vamos a hacer para encontrar la posición del cero y así poder calcularlo es generar
una lista con los signos de los valores de la lista yy y la dibujamos
(%i7) lis:signum(yy)$
wxplot2d([[discrete,lis]],[y,-1.1,1.1]);
(%t7) (Graphics)
184
4
lista 1
2 función
0 0.5
-2
y(t)
y(t)
0
-4
-6 -0.5
-8
-1
-10
0 0.5 1 1.5 2 2.5 3 3.5 4 0 100 200 300 400 500 600 700 800
x(t) x(t)
En la segunda gráfica se ve claramente los tres ceros así como su posición en la lista yy.
Lo que haremos es buscar donde ocurre el primer cambio de signo en la lista yy y eso
nos dará la posición del cero. Conocida la posición podemos encontrar el correspondiente
valor en a lista xx. Para ello usaremos el comando sublist_indices que discutimos en la
página 16 y que usamos en combinación con las funciones indeterminadas lambda para
encontrar los extremos de una función en la sección 8.4.
Por ejemplo si escribimos
(%i9) block([ll,lsig],ll:-lis,lsig:sublist_indices(ll,lambda([x],x=1.0)));
(%o9) [1,2,3,4,5,6,7 ... ,626,627,628,629]
(%i10) block([ll,lsig],ll:-lis,lsig:sublist_indices(ll,lambda([x],x=-1.0)));
(%o10) [232,233,234,235, ..., 799,800,801]
Conviene recordar que por el momento nos interesa encontrar únicamente el primer cero
de nuestra función, así que definiremos dos funciones, una para encontrar el primer cero
cuando la función empieza tomando valores positivos y otra para cuando empieza con
valores negativos
Es importante destacar que las órdenes anteriores están pensadas para listas numéricas
em coma flotante, así que en caso de que no lo sean hay que usar el comando float.
Teniendo en cuenta que
podemos combinarla para crear un único comando que nos dé la posición del primer
cambio de signo de cualquier lista de números
(%i20) pc:poscero(yy);
(pc) 232
(%i21) poscero(-yy);
(%o21) 232
(%i24) yy[pc-1]; yy[pc]; yy[pc+1];
(%o22) -0.01384072053604195
(%o23) 0.001766064549686498
(%o24) 0.01719538434482167
que nos dice que, efectivamente, el primer cambio de signo de f (x) ocurre entre la posi-
ción pc-1=231 y pc=232 de la lista yy de sus valores. Conocida dicha posición podemos
calcular los valores de la x
y a partir de ellas encontramos una aproximación del primer cero por ejemplo así
(%i28) cero(lista,m):=block([ll],ll:lista,(ll[m-1]+ll[m]+ll[m+1])/3);
(%i29) z1:cero(xx,poscero(yy));
(z1) 1.155
186
Pasemos a describir como encontrar el segundo cero. Para ello lo que haremos es crear
una nueva lista, que llamaremos yy2, que obtendremos tras quitarle a la lista original yy
los elementos que tienen el signo constante. Ello lo haremos con el comando rest que ya
hemos usado varias veces a lo largo de este libro (ver página 15)
y para la nueva lista encontramos la posición del primer cambio de signo y su cero con las
órdenes poscero y cero, respectivamente
(%i32) pc2:poscero(yy2);
(pc2) 313
(%i33) z2:cero(xx2,pc2);
(z2) 2.72
Finalmente repetimos estas operaciones hasta cubrir todos los ceros que hemos visto en
las gráficas del principio de esta sección
Finalmente comparamos los ceros numéricos con los reales de nuestro ejemplo
Conviene hacer notar que hay muchas formas de definir la orden cero que usamos aquí.
Por ejemplo, encontrados los dos puntos donde cambia el signo de nuestra lista podemos
unir dichos puntos por una recta y ver donde dicha recta corta el eje de las x. Dicha
función es la siguiente:
(%i38) newcero(listax,listay,m):=block([lx,ly,pc],pc:m,lx:listax,ly:listay,
lx[pc-1]-ly[pc-1]*(lx[pc]-lx[pc-1])/(ly[pc]-ly[pc-1]));
d2 d2
m y(t) = −mg + Frx (v), m x(t) = Fry , (8.7.2)
dt2 dt2
con las siguientes las condiciones iniciales
d d
y(0) = h, vy (0) = y(0) = 0, x(0) = 0, vx = x(0) = v0 . (8.7.3)
dt dt
En (8.7.2) Frx y Fry son las componentes horizontal y vertical de la fuerza de rozamiento
del medio, respectivamente, m es la masa de la bola, g la aceleración de la gravedad.
188
Existen varias expresiones para el valor de dicha fuerza de rozamiento. Una posibilidad
es que se cumpla la Ley de Stokes que establece que dicha fuerza es proporcional a la
velocidad y actúa en sentido contrario a la misma, i.e.,
dx dy
Frx = −3πηd vx , Fry = −3πηd dvy , vx = , vy = ,
dt dt
donde η es el coeficiente de viscosidad del medio. Usando que m = πρd3 /6, donde ρ es
la densidad de la esfera, obtenemos el siguiente sistema de ecuaciones desacopladas (es
decir cada ecuación es independiente de la otra):
d2 y dy d2 x dx 18η
2
= −g − α , 2
= −αd , α= .
dt dt dt dt ρd2
En este caso, el problema es relativamente sencillo de resolver pues tenemos dos ecua-
ciones diferenciales que podemos resolver independientemente una de la otra y de forma
exacta. La solución es:
g e−α t + α t − 1
y(t) = h − , (8.7.4)
α2
v0 1 − e−α t
x(t) = , (8.7.5)
α
con las condiciones iniciales (8.7.3). La primera ecuación (8.7.4) nos permite encontrar
el tiempo que tarda una gota en caer y, conociendo dicho tiempo, podemos encontrar con
la segunda ecuación (8.7.5) la distancia xc a la que cae. Para encontrar el tiempo de caída
hemos de resolver la ecuación
hα2
F (t) = e−α t − − 1 + α t = 0, (8.7.6)
g
que equivale a encontrar los ceros de la función F (t) que está dada de forma implícita
y por tanto podemos usar los comandos estándar como por ejemplo find_root. Por ello
consideraremos un problema más complicado.
En general es bien sabido que la fuerza de rozamiento sigue la Ley de Stoke si el número
de Reynolds definido por
ρa vd
Re = ,
η
q
donde ρa es la densidad del medio y v = vx2 + vy2 , es mucho más pequeño que la unidad.
En general, la fuerza de rozamiento es igual a
2
~ πd ρa
Fr = − Cd (v)v~v , (8.7.7)
8
Estudiemos primero el caso del tiro parabólico sin resistencia del aire. En este caso las
ecuaciones son (8.7.2) cuando Fr = 0. Aunque en este caso el problema se puede resolver
analíticamente lo haremos de forma numérica para luego compararlo con el caso cuando
hay resistencia del aire.
Comenzaremos cargando el paquete proglist.mac que hemos creado para poder usar
las órdenes del apartado anterior.
(%i1) load("proglist.mac");
(%i5) g:9.8$ h:20$ v0y:0$ v0x:10$
(%i7) define(fy(t,y,dy,x,dx) ,-g);
define(fx(t,y,dy,x,dx) ,0);
(%o6) fy(t,y,dy,x,dx):=-9.8
(%o7) fx(t,y,dy,x,dx):=0
Para resolver el sistema (8.7.9) usamos la orden rk que ejecuta un Runge-Kutta (ver la
página 107)
190
de donde vemos que tiene un cero. Calculamos la posición del mismo en la lista así como
su valor con los comandos poscero y newcero, respectivamente
(%i14) pc:poscero(yyl);
(pc) 204
(%i15) tc:newcero(til,yyl,pc);
(tc) 2.020304358780547
(%i18) nxl:rest(xxl,pc-length(yyl))$
nyl:rest(yyl,pc-length(yyl))$
lxl:last(nxl);
(lxl) 20.30000000000002
Lo anterior nos dice que la esfera cae al suelo en 2,02 segundos y alcanza los 20,30 metros.
Dibujemos la trayectoria (ver figura 8.19, izquierda)
(%i19) wxdraw2d(grid=true,line_type=solid,line_width=5,nticks=100,
xaxis =true,xaxis_type=solid,yaxis =true,yaxis_type=solid,
xlabel="x(t)",ylabel="y(t)", point_type=filled_circle,
point_size =1, color=red, title="Trayectoria",
yrange=[0,h+.2], xrange=[0,lxl+.2], points(nxl,nyl) );
Vamos ahora a resolver el caso cuando la esfera cae con resistencia del aire, es decir
cuando las ecuaciones de movimiento vienen dadas por el sistema (8.7.9).
Comenzamos fijando los parámetros de las ecuaciones
(%i27) define(alphanew(dx,dy),(18*eta*(((dy^2+dx^2)^(1/4)*
sqrt((d*rhoa)/eta))/delta0+1)^2)/(d^2*rho));
define(fy(t,y,dy,x,dx) ,-g-alphanew(dx,dy)*dy);
define(fx(t,y,dy,x,dx) ,-alphanew(dx,dy)*dx);
(%i41) pc1:poscero(yy);
(pc1) 259
tc1:newcero(ti,yy,pc1);
(tc1) 2.576044214168774
(%i43) nx:rest(xx,pc1-length(yy))$
ny:rest(yy,pc1-length(yy))$
lx:last(nx);
(lx) 12.87648490726287
De lo anterior se sigue que el tiempo de caída es 2,56 segundos y alcanza 12,88 metros, es
decir, tarda más en caer pero tiene un menor alcance. Con los datos podemos dibujar la
trayectoria de nuestra esfera dibujando los puntos (x(t), y(t)) (ver figura 8.19, derecha)
(%i44) wxdraw2d(grid=true,line_type=solid,line_width=5,nticks=100,
xaxis=true,xaxis_type=solid,yaxis=true,
yaxis_type=solid,xlabel="x(t)",ylabel="y(t)",
point_type=filled_circle,point_size =1,
color=blue,title="Trayectoria",
yrange=[0,h+.2],xrange=[0,lx+.2],points(nx,ny));
192
Trayectoria Trayectoria
20 20
15 15
y(t)
y(t)
10 10
5 5
0 0
0 5 10 15 20 0 2 4 6 8 10 12
x(t) x(t)
Figura 8.19: Trayectoria de la esfera sin (izquierda) y con (derecha) rozamiento del aire.
Trayectoria
20
rozamiento
sin rozamiento
15
y(t)
10
0
0 5 10 15 20
x(t)
y lo podemos comparar con los resultados de la caída libre sin rozamiento (ver figura 8.20
(izquierda))
(%i45) wxdraw2d(grid=true,line_type=solid,line_width=5,nticks=100,
xaxis =true, xaxis_type=solid,yaxis=true,
xlabel="x(t)",ylabel="y(t)",point_type=filled_circle,
title="Trayectoria",yrange=[0,h+.2],xrange=[0,lxl+.2],
point_size=1,color=blue,key="rozamiento",points(nx,ny),
point_size=1,color=red,key="caída libre",points(nxl,nyl));
Finalmente, haremos una película de la caída de la gota con y sin rozamiento como una
imagen gif animada (un fotograma se puede ver el la figura 8.20 (derecha))
(%i46) pt:float(floor(ti*10.0)/10)$
(%i47) draw(terminal=animated_gif,delay=1,file_name="peli-caida-comp",
makelist(gr2d( line_width = 3,dimensions = [1000,800],
xaxis=true,xaxis_type=solid,yaxis=true,xlabel="x(t)",ylabel="y(t)",
grid=true,key_pos=top_left,font ="Arial",font_size=24,
point_type=filled_circle,yrange=[0,h+.2],xrange=[0,lxl+.1],
point_size=2,color=red, points(makelist([xxl[ii],yyl[ii]],ii,1,kk)),
point_size=2,color=blue,points(makelist([nx[ii],ny[ii]],ii,1,kk)),
R. Álvarez Nodarse Introducción a M AXIMA CAS 193
Hemos usado la secuencia floor(ti*10.0)/10 para redondear hasta una cifra decimal
el valor de la variable ti. Si queremos dos cifras habrá que multiplicar por 100 y dividir
por 100, etc. Hay situaciones en las que M AXIMA imprime en pantalla en vez del número
redondeado hasta la cantidad de cifras pero seguido de muchos ceros y terminado en uno.
Por ejemplo, puede ocurrir que tengamos el número 552,5527666856816 y que si usamos la
secuencia anterior para aproximarlo con 2 cifras obtengamos el valor 552,5600000000001.
Eso ocurre por diversas causas y tiene una solución muy sencilla que consiste en controlar
la precisión de las salidas (output). Eso lo hace la variable fpprintprec que por defecto
es 16 (recordemos que M AXIMA trabaja en doble precisión). En este caso basta definirla
en 15, e.g, fpprintprec:15 y se resuelve el problema.
gi (x, y, z, u, v, w) = 0, i = 1, 2, 3,
dx =Du f1 du + Dv f1 dv + Dw f1 dw,
dy =Du f2 du + Dv f2 dv + Dw f2 dw, (8.8.2)
dz =Du f3 du + Dv f3 dv + Dw f3 dw,
dx =Du f1 du + Dv f1 dv,
dy =Du f2 du + Dv f2 dv, (8.8.3)
dz =Du f3 du + Dv f3 dv
11
Por simplicidad describiremos el caso de dos variables independientes. El caso general es análogo.
194
donde
∂ ∂w ∂ ∂ ∂ ∂ ∂w ∂ ∂ ∂
Du = + = + wu , Dv = + = + wv .
∂u ∂u ∂w ∂u ∂w ∂v ∂v ∂w ∂v ∂w
Si el determinante
D f Dv f1
∆ = u 1
6= 0,
Du f2 Dv f2
entonces las dos primeras ecuaciones de (8.8.3) se pueden resolver expresándose las dife-
renciales du y dv en función de las dx y dy
1
du = Dv f2 dx − Dv f1 dy ,
∆
(8.8.4)
1
dv = − Du f2 dx + Du f1 dy ,
∆
de donde deducimos
1
zx = Du f3 Dv f2 − Dv f3 Du f2 = F1 (u, v, w, wu , wv ),
∆
(8.8.5)
1
zy = − Du f3 Dv f1 + Dv f3 Du f1 = F2 (u, v, w, wu , wv ).
∆
Si queremos obtener las expresiones de las segundas derivadas prodecemos como sigue:
Calculamos
(%i9) linsolve([eq1,eq2],[del(r),del(phi)])$
sol1:trigsimp(%);
(%o10) [del(r)=sin(phi)*del(y)+cos(phi)*del(x),
del(phi)=cos(phi)*del(y)-sin(phi)*del(x))/r]
A continuación seleccionamos los coeficientes delante de ambos diferenciales que nos dan
los valores de las derivadas zx y zy , respectivamente
(%i14) zx:coeff(a,del(x),1);
(%o14) cos(phi)*('diff(w,r,1))-(sin(phi)*('diff(w,phi,1)))/r
(%i15) zy:coeff(a,del(y),1);
(%o15) sin(phi)*('diff(w,r,1))+(cos(phi)*('diff(w,phi,1)))/r
Para calcular las segundas derivadas calculamos el diferencial de dzx = zxx dx + zyx dy
(%i16) eqdzx:diff(zx);
(%i17) subst(sol1,eqdzx)$
b:expand(%);
(%i19) zxx:coeff(b,del(x),1);
(%o19) cos(phi)^2*('diff(w,r,2))+(sin(phi)^2*('diff(w,r,1)))/r+
(sin(phi)^2*('diff(w,phi,2)))/r^2
-(2*cos(phi)*sin(phi)*('diff(w,phi,1,r,1)))/r
+(2*cos(phi)*sin(phi)*('diff(w,phi,1)))/r^2
196
(%i20) eqdzy:diff(zy)$
(%i21) subst(sol1,eqdzy)$ c:expand(%);
(%i23) zyy:coeff(c,del(y),1);
(%o23) sin(phi)^2*('diff(w,r,2))+(cos(phi)^2*('diff(w,r,1)))/r+
(cos(phi)^2*('diff(w,phi,2)))/r^2
+(2*cos(phi)*sin(phi)*('diff(w,phi,1,r,1)))/r
-(2*cos(phi)*sin(phi)*('diff(w,phi,1)))/r^2
(%i24) zxx+zyy$
(%i25) trigsimp(%); expand(%);
(%o26) 'diff(w,r,2)+'diff(w,r,1)/r+'diff(w,phi,2)/r^2
(%i27) subst(w=z,%);
(%o27) 'diff(z,r,2)+'diff(z,r,1)/r+'diff(z,phi,2)/r^2
que nos da
d2 z 1 dz 1 d2 z
2
+ + 2 2 = 0.
dr r dr r dϕ
Como ejercicio se propone encontrar las expresiones en las nuevas variables de las
siguientes ecuaciones aplicando los correspondientes cambios de variables:
Un reto interesante para el lector puede ser programar con M AXIMA el caso de funcio-
nes de tres variables. Como ejemplo proponemos escribir la ecuación de Laplace wxx +
wyy + wzz = 0 en coordenadas esféricas: x = r cos(φ) sin(θ), y = r sin(φ) sin(θ), z =
r cos(θ), siendo la función w(x, y, z) = w(r, θ, φ).
Aunque el M AXIMA tiene la orden taylor que mencionamos al final del apartado 2.3
vamos a programar una función que calcule el diferencial Dk f (a) de cualquier orden de
una función escalar de dos variables en cierto punto a y que actué sobre cierto vector h.
La idea es mostrar al lector como resolver un problema paso a paso, y particularmente
como corregir los distintos problemas que van a ir apareciendo. Vamos a usar la siguiente
fórmula [7, pág. 463] para el k−ésimo diferencial de una función f :
k k
∂ k f (a) ∂ k
k
X X ∂
D f (a)(h) = ··· hi · · · hik = h1 + · · · + hn f (a),
∂xi1 · · · ∂xik 1 ∂x1 ∂xn
i1 =1 ik =1
(8.9.1)
R. Álvarez Nodarse Introducción a M AXIMA CAS 197
Como punto de partida usaremos los diferenciales de orden 1 y 2, cuyas expresiones son,
respectivamente,
∂f (x0 , y0 ) ∂f (x0 , y0 )
Df (x0 , y0 )(x, y) = (x − x0 ) + (y − y0 ),
∂x ∂y
∂ 2f (x0 , y0 ) ∂ 2f (x0 , y0 ) ∂ 2f (x0 , y0 )
D2f (x0 , y0 )(x, y) = (x−x 0 )2
+2 (x−x 0 )(y − y 0 )+ (y−y0 )2 .
∂x2 ∂x∂y ∂y 2
∂ i+j f (x, y)
Lo primero que tenemos que conseguir es implementar las derivadas eva-
∂xi ∂y j
luadas en un punto dado (x0 , y0 ):
(%i1) dd:diff(f(x,y),x,i,y,j);
(%o1) 'diff(f(x,y),x,i,y,j)
(%i2) ev(dd,x=0,y=0);
diff: variable must not be a number; found: 0
-- an error. To debug this try: debugmode(true);
(%i3) dd:diff(f(x,y),x,i,y,j); ev(dd,x=x0,y=y0);
(%o3) 'diff(f(x,y),x,i,y,j)
(%o4) 'diff(f(x0,y0),x0,i,y0,j)
Esta primera secuencia nos muestra que la evaluación de la derivada de forma genérica no
es trivial pues en ambos casos M AXIMA intenta sustituir la variable por su valor. En el caso
del cero nos da un error obvio, y en el caso de una valor genérico x0 nos cambia todas
las variables por los nuevos valores como si estos fueran variables nuevas. Lo anterior
nos induce a pensar que quizá actuando sobre una función concreta vamos a obtener el
resultado deseado, lo cual se confirma con la secuencia siguiente:
(%i5) define(f(x,y),exp(x)*sin(y)+y^2*sin(x));
dd:diff(f(x,y),x,2,y,2);
ev(dd,x=0,y=0);
(%o5) f(x,y):=%e^x*sin(y)+sin(x)*y^2
(%o6) -%e^x*sin(y)-2*sin(x)
(%o7) 0
(%i8) ev(dd,x=x0,y=y0);
(%o8) -%e^x0*sin(y0)-2*sin(x0)
Ahora, si nos interesa definir una función para el cálculo de la derivada evaluada en un
∂ i+j f (x0 , y0 )
punto, conviene poder obtener el valor en una sola línea.
∂xi ∂y j
Para eso utilizaremos la orden block que ya vimos antes en la página 55. Así tenemos
198
(%i10) jacobian([f(x,y)],[x,y]);ev(%,x=0,y=0);%.[x,y];
(%o10) matrix([%e^x*sin(y)+cos(x)*y^2,%e^x*cos(y)+2*sin(x)*y])
(%o11) matrix([0,1])
(%o12) y
(%i13) hessian(f(x,y),[x,y]);ev(%,x=0,y=0);[x,y].%.[x,y];
(%o13) matrix([%e^x*sin(y)-sin(x)*y^2,%e^x*cos(y)+2*cos(x)*y],
[%e^x*cos(y)+2*cos(x)*y,2*sin(x)-%e^x*sin(y)])
(%o14) matrix([0,1],[1,0])
(%o15) 2*x*y
Está claro que el diferencial de orden k será una suma que contendrá todas las posibles
derivadas de orden k de nuestra función. Ello nos obliga a usar un bucle para calcular
todas las posibles derivadas. Para ello usaremos el comando for (ver página 74):
(%i16) k:1$
for j:0 thru k do
for i:0 thru k do
if i+j = k then
block([dd], dd:diff(f(xx,yy),xx,i,yy,j),
b[i,j]:ev(dd,xx=0,yy=0)*x^i*y^j)
else b[i,j]:0 $
Así, en la orden anterior tenemos un bucle en la variable j que toma los valores de j =
0, 1, . . . , k y para cada uno de ellos realiza un bucle interior en la variable i que toma los
valores de i = 0, 1, . . . , k y que realiza la acción del cálculo de la derivada. Ahora bien,
como sabemos, para la diferencial de orden k sólo nos interesan los valores de i y j tales
que i + j = k, es por ello que al realizar el segundo bucle la acción sólo debe darnos
los valores de la derivada que nos interesan. Por ello usamos la orden if que ya usamos
cuando definimos funciones a trozos en el apartado 2.3. El resultado es una cantidad bi,j
que toma los valores de las derivadas parciales de orden k si i + j = k o cero en caso
contrario. Con esos valores podemos fácilmente calcular la diferencial de orden 1
de orden 2,
(%i19) k:2$
for j:0 thru k do for i:0 thru k do if i+j = k then
block([dd], dd:diff(f(xx,yy),xx,i,yy,j),
b[i,j]:ev(dd,xx=0,yy=0)*x^i*y^j) else b[i,j]:0$
sum(sum(binomial(k,i)*b[i,j],i,0,k),j,0,k);
(%o21) 2*x*y
R. Álvarez Nodarse Introducción a M AXIMA CAS 199
y así sucesivamente. Conviene observar que los diferenciales de orden 1 y 2 coinciden con
los calculados anteriormente usando el jacobiano y la matriz hessiana.
El próximo paso es definir una función para calcular el diferencial de orden arbitrario,
para lo que usaremos la fórmula (8.9.1):
(%i22) Diff(k):=block( for j:0 thru k do for i:0 thru k do if i+j=k then
block([dd], dd:diff(f(xx,yy),xx,i,yy,j),
b[i,j]:ev(dd,xx=0,yy=0)*(x)^i*(y)^j) else b[i,j]:0,
sum(sum(binomial(k,i)*b[i,j], i , 0, k) , j,0,k))$
(%i23) Diff(0);
(%o23) 0
(%i24) Diff(1);
(%o24) y
(%i25) Diff(2);
(%o25) 2*x*y
Ya puestos, definimos una función que dependa de los valores donde vamos a evaluar
(x0 , y0 )
(%o36) 2*%pi*x*y-x*y-y-%pi^2*x+%pi*x+%pi
(%i37) taM:expand(taylor(exp(x)*sin(y)+y^2*sin(x),[x,y],[0,%pi],2));
(%o37) 2*%pi*x*y-x*y-y-%pi^2*x+%pi*x+%pi
(%i38) ta-taM;
(%o38) 0
Las últimas entradas son para comparar la salida de nuestra orden TAY con la salida de la
orden taylor de M AXIMA las cuales, como se ve, coinciden.
Vamos ahora a mejorar nuestra función Diff1. Vamos a intentar que nuestra orden
funcione sin tener que definir previamente la función de trabajo. Ante todo limpiamos la
memoria con un kill(all) y comenzamos
(%i1) define(f(x,y),exp(x)*sin(y)+y^2*sin(x));
(%o1) f(x,y):=%e^x*sin(y)+sin(x)*y^2
(%i2) Diff1(k,x0,y0):=block( for j:0 thru k do for i:0 thru k do
if i+j=k then block([dd],
dd:diff(f(xx,yy),xx,i,yy,j),
b[i,j]:ev(dd,xx=x0,yy=y0)*(x-x0)^i*(y-y0)^j)
else b[i,j]:0,
sum(sum(binomial(k,i)*b[i,j],i,0,k),j,0,k));
(%i3) d1:Diff1(1,x0,y0);
(%o3) (x-x0)*(%e^x0*sin(y0)+cos(x0)*y0^2)+(y-y0)*(%e^x0*cos(y0)
+2*sin(x0)*y0)
(%i4) d10:Diff1(1,0,0);
(%o4) y
(%i5) Diferencial(expr,x,y,x0,y0,k):=block([b],
for j:0 thru k do for i:0 thru k do if i+j=k then
block([dd], dd:diff(expr,x,i,y,j),
b[i,j]:ev(dd,x=x0,y=y0)*(x-x0)^i*(y-y0)^j) else b[i,j]:0,
sum(sum(binomial(k,i)*b[i,j],i,0,k),j,0,k));
(%i6) Diferencial(f(x,y),x,y,x0,y0,1);
(%o6) (x-x0)*(%e^x0*sin(y0)+cos(x0)*y0^2)+(y-y0)*(%e^x0*cos(y0)
+2*sin(x0)*y0)
(%i7) %-d1;
(%o7) 0
(%i8) Diferencial(cos(x)+sin(y),x,y,x0,y0,1);
(%o8) (y-y0)*cos(y0)-(x-x0)*sin(x0)
(%i9) Diferencial(f(x,y),x,y,0,0,1);
(%o9) y
(%i10) Diferencial(f(xx,yy),xx,yy,0,0,1);
(%o10) xx*(%e^xx*sin(yy)+cos(xx)*yy^2)+yy*(%e^xx*cos(yy)+2*sin(xx)*yy)
(%i11) Diferencial(expr,u,v,u0,v0,k):=
block([b,dd,xxx,yyy,ee,newexpr,newexpr1],
newexpr:subst(xxx,u,expr),
newexpr1:subst(yyy,v,newexpr),
for j:0 thru k do
for i:0 thru k do
if i+j = k then
block([dd], dd:diff(newexpr1,xxx,i,yyy,j),
b[i,j]:ev(dd,xxx=u0,yyy=v0)*(u-u0)^i*(v-v0)^j)
else b[i,j]:0,
sum(sum(binomial(k,i)*b[i,j],i,0,k),j,0,k))$
(%i12) Diferencial(f(x,y),x,y,0,0,4);
(%o12) 4*x^3*y-4*x*y^3
(%i13) Diferencial(f(xx,yy),xx,yy,0,0,4);
(%o13) 4*xx^3*yy-4*xx*yy^3
Ya estamos listos para definir nuestra propia orden para calcular el polinomio de Taylor
de orden k de una función de dos variables expr en las variables u y v en el punto u0 y v0
(%i14) TAYLOR(expr,u,v,u0,v0,k):=block(
expand(sum((1/l!)*Diferencial(expr,u,v,u0,v0,l),l,0,k)))$
(%i15) TAYLOR(f(x,y),x,y,x0,y0,2);
(%i16) expand(taylor(f(x,y),[x,y],[x0,y0],2)-%);
(%o16) 0
(%i17) TAYLOR(f(x,y),x,y,0,0,2);
(%o17) x*y+y
(%i18) taylor(f(x,y),[x,y],[0,0],2);
(%o18)/T/ y*x+y+...
(%i19) TAYLOR(cos(x^2+y),x,y,%pi,0,6);
(%i20) expand(taylor(cos(x^2+y),[x,y],[%pi,0],6)-%);
(%o20) 0
Como ejercicio al lector se propone adaptar las funciones anteriores al caso de funcio-
nes de tres variables.
En el apartado 4.3 hemos discutido como podemos realizar un ajuste de mínimos cua-
drados de un conjunto de datos. Nuestro objetivo es ahora modificar los correspondientes
comandos de M AXIMA para el caso cuando tenemos que ajustar los datos pero teniendo
en cuenta los correspondientes pesos de cada uno de ellos.
202
N
X
(yk − ffit (xk ))2
i=1
sea mínima. Este es el típico problema de mínimos cuadrados que resuelve M AXIMA con los
comandos lsquares_estimates_approximate o lsquares_estimates. Pero cambiemos el
problema. Imaginemos que ahora la expresión a minimizar es algo más complicada pues
cada valor (xk , yk ) tiene un cierto peso, no igual para cada uno, digamos ρk . Está claro
que lo que hay que minimizar es la cantidad
N
X
ρk (yk − ffit (xk ))2
i=1
¿Cómo proceder? Está claro que con la orden lsquares_estimates no hay mucho que
hacer pues su sintaxis, recordemos, es
donde datos es una matriz de datos, lista de variables, es una lista con el nom-
bre de las variables correspondiente a cada columna de la matriz de datos, lista de
parametros es una lista con los parámetros del modelo y ecuacion es la ecuación que
vamos usar para el ajuste de datos. Sin embargo, teníamos la opción numérica que es
más flexible. Recuperando el ejemplo de la página 81 tenemos, por un lado, el comando
lsquares_mse(datos, var , ec) que genera la expresión del error cuadrático medio de
los datos de nuestra matriz de datos para la ecuación ec en la lista de variables var. Por
ejemplo, supongamos que tenemos una matriz mm de dos columnas y N filas y queremos
ajustar los datos con la recta y = ax + b. Entonces lsquares_mse genera la siguiente salida
A continuación usamos
lsquares_estimates_approximate(mse, [a,b])
que lo que hace es encontrar los valores de a y b que minimicen la expresión (%i2).
Visto esto está claro lo que podemos hacer: construir la suma mse correspondiente, por
ejemplo de la siguiente forma
donde la primera fila le corresponde a las x, la segunda a las y y la tercera a los errores de
y. Vamos a hacer un ajuste con la función f (x) = a(1 − exp(−bx)).
(%i8) pp(x):=a*(1-exp(-b*x));
(%i9) mse : lsquares_mse (mm, [x, y], y=pp(x));
sol:lsquares_estimates_approximate(mse, [a,b]);
(%o9) sum((mm[i,2]-a*(1-%e^(-b*mm[i,1])))^2,i=1,1,6)/6
(%o10) [[a=213.8094059887529,b=0.547237523991729]]
(%i19) ssw:sum((1/ee[i])*(pp(mm[i,1])-mm[i,2])^2,
i,1,length(mm))/length(mm);
solw:lsquares_estimates_approximate(ssw, [a,b]);
(%o20) [[a=225.1712692206121,b=0.4007843817891243]]
200
150
100
50
0
0 2 4 6 8 10
Como hemos visto en (4.4.3), para la construcción del polinomio interpolador de La-
grange sólo usamos los valores (xi , f (xi )), no obstante, en gran cantidad de problemas
reales además de los valores yi = f (xi ) se conocen los valores de las derivadas de la fun-
ción yi0 = f 0 (xi ). Así, tenemos en general el siguiente problema: Dado un intervalo (a, b),
sean xi , i = 1, 2, .., n ciertos valores prefijados del mismo y supongamos que a cada uno de
(k−1)
ellos le corresponden la lista de valores yi , yi0 ,..., yi . El problema consiste en encontrar
un polinomio Hm (x), de orden a lo más m = kn − 1, que coincida en los puntos xi con los
(k−1)
valores yi y el de sus respectivas derivadas hasta orden k − 1, Hm (x), con los valores
(k−1)
yi0 ,..., yi , o sea, Hm (x) es tal que para i = 1, 2, . . . , n,
0 (k−1)
Hm (xi ) = yi , Hm (xi ) = yi0 , ... (k−1)
Hm (xi ) = yi .
[1] Maxima 5.42.0 Manual (versión original inglés, más actualizada) o Manual de Refe-
rencia (versión 5.35.1) (traducción al castellano) Ver online o descargar el fichero pdf
desde http://maxima.sourceforge.net/documentation.html
[6] G.F. Simmons, Ecuaciones diferenciales: con aplicaciones y notas históricas. McGraw-
Hill, 1993.
[7] V.A. Zorich, Mathematical Analysis, tomos I y II, Springer Verlag, 2004.
207