# PRÁCTICA 1. ANÁLISIS COMPLEJO I y II.

## Análisis Complejo I:
Operaciones básicas con números complejos.

Veremos incialmente algunos comandos específicos para trabajar con 
números complejos. En MAXIMA la unidad imaginaria se representa por 

%i

Por ejemplo para definir una variable z1 que contenga el número complejo 

     3-2i

escribiremos:

z1: 3 - 2*%i;

EJERCICIO 1: Define los siguientes números complejos:

a) 1 + i
b) -2 + i*sqrt(3)
c) -2-4*i

/* RESPUESTA EJERCICIO 1 */;

Para obtener la parte real se utiliza la función

            realpart(z)

Por ejemplo, para encontrar la parte real del complejo z1, escribimos:

real_z1: realpart(z1);

mientras que para la parte imaginaria utilizaremos la función

            imagpart(z)

por ejemplo

imag_z1 : imagpart(z1);

EJERCICIO 2: Encuentra las partes real e imaginaria de los complejos definidos en el ejercicio 1.

/* RESPUESTA EJERCICIO 2 */;

A veces MAXIMA nos devuelve el número complejo indicando la parte imaginaria en primer lugar, 
por ejemplo si definimos el complejo z2 como  -1 + 4*i

z2:-1+4*%i;

Para que siempre escriba en primer lugar la parte real seguida de la parte imaginaria usaremos la
variable del sistema 

            powerdisp

Por defecto dicha variable contiene el valor false, es decir, la opción está desactivada.

powerdisp;

Podemos cambar el valor a 

            true

powerdisp:true$

Y comprobaremos que en este caso el parte imaginaria está en segundo lugar en la forma usual:

z2;

OPERACIONES ARITMÉTICAS CON NÚMEROS COMPLEJOS

Podemos realizar operaciones en forma binómica de forma directa. 

SUMA
    Se utiliza el operador +

suma:z1+z2;

RESTA
    Se utiliza el operador -

resta:z1-z2;

PRODUCTO
    Se utiliza el operador *

producto: z1*z2;

Observemos que nos da una expresión literal. Para calcular la forma binómica del producto se utiliza la función

            expand

expand(producto);

DIVISIÓN
    Se utiliza el operador /

division:z1/z2;

Como vemos ocurre lo mismo que con el producto, MAXIMA deja la operación indicada.

Si utilizamos el comando expand, obtenemos un resuoltado inesperado:

expand(division);

Vemos que sólo separa la parte real e imaginaria en el numerador. 

Para obtener el resultado en forma binómica se utiliza la función

            rectform

rectform(division);

EJERCICIO 3: Realiza las siguientes operaciones expresando el resultado en forma binómica.

a) Define los números complejos z1 = 1 + i y z2 = 2-3i.
b) Calule z1+z2, z1-z2, z1*z2 y z1/z2.

/* RESPUESTA EJERCICIO 3 */;

MÓDULO: Podemos calcular el módulo de z usando 

            abs(z) 

o 

            cabs(z)

modulo: abs(z1);

modulo2: cabs(z1);

NOTA: Si usamos abs(z) para calcular el módulo del complejo z, 
obtendremos el valor absoluto de z, y no el resultado dado por 
cabs(z), que nos da (x^2+y^2)^(1/2). La opción abs(z) suele 
usarse cuando se utilizan cálculos simbólicos (por ejemplo, 
calcular límites, derivadas, integrales,...)

Veamos la diferencia entre los dos comandos. Si definimos z como x+iy

kill(all)$
powerdisp:true$
z:x+%i*y;

Aplicamos a z ambos comandos, abs y cabs, para comprobar la diferencia entre ellos

abs(z);
cabs(z);

ARGUMENTO:  Para el cálculo del argumento utilizamos 

            carg

Calcularemos a continuación el argumento del complejo 1+i

z1: 1 + %i;
argumento: carg(z1);

FORMA POLAR: Podemos expresar el complejo z en forma polar |z|·e^(i·arg(z)), 
utilizando su módulo y su argumento

modulo:abs(z1);
z1_polar : modulo*exp(%i*argumento);

O directamente mediante la función 

        polarform

polarform(z1);

CONJUGADO:   Para hallar el conjugado de un número complejo usamos el comando

        conjugate

z1;
conjugate(z1);

POTENCIAS NATURALES: 

Podemos calcular potencias naturales de z con el operador ^

z1^2;
expand(%);

También podemos calcular potencias enteras de z usando el mismo operador ^

z1^(-2);
expand(%);
rectform(%);

RAÍCES 

A la hora de calcular raíces complejas, hemos de tener en cuenta que MAXIMA 
no las va a obtener todas (sabemos que todo complejo z tiene n raíces n-ésimas), 
sino que nos va a dar la primera de ellas (recordemos que las demás siempre tienen
el mismo módulo pero se diferencian en el argumento):

z2: 1+%i;
raiz_cuadrada1: z2^(1/2);
raiz_cuadrada1_bin: rectform(raiz_cuadrada1);
raiz_cuadrada1_pol: polarform(raiz_cuadrada1);

Para econtrar el resto de raíces, hay que recordar que la diferencia en los argumentos 
entre dos raíces consecutivas, viene dada por

2 pi / n 

Por tanto para los dos casos anteriores, lo único que tenemos que hacer es sumar 2%pi/n
al argumento, o multiplicar por un número complejo de módulo 1 y argumento 2*%pi/n.

Calculamos el módulo común de todas las raíces

modulo : cabs(raiz_cuadrada1);

Calculamos el incremento en el argumento, en este caso como es 
raíz cuadrada n=2

darg : 2*%pi/2;

Calculamos el argumento de cada raíz

arg1 : trigreduce(carg(raiz_cuadrada1_pol));
arg2 : arg1 + darg;

Calculamos las dos raíces cuadradas.

raiz_cuadrada1 : modulo*%e^(%i*arg1);
raiz_cuadrada2 : modulo*%e^(%i*arg2);

Vamos a repetir el proceso para calcular la raíz cubica de z3

Calculamos la 1ª raíz

z2:1+%i$
raiz_cubica1: z2^(1/3);
rectform(raiz_cubica1);
polarform(raiz_cubica1);

Calculamos módulo común

modulo : cabs(raiz_cubica1);

Calculamos el incremento en el argumento que ahora es n=3

darg : 2*%pi/3;

Calculamos el argumento de cada raíz

arg1 : trigreduce(carg(raiz_cubica1));
arg2 : arg1 + darg;
arg3 : arg2 + darg;

Calculamos todas las raíces

raiz_cubica1 : modulo*%e^(%i*arg1);
raiz_cubica2 : modulo*%e^(%i*arg2);
raiz_cubica3 : modulo*%e^(%i*arg3);

O en forma binómica

rectform(raiz_cubica1);
rectform(raiz_cubica2);
rectform(raiz_cubica3);

EJERCICIO 4: Resuelve el siguiente problema
1.- Calcula en forma polar los números complejos: 2i, -3i, i, 3, -3+i√(3), (1+i)/(1-i)
2.- Resuelve las siguientes ecuaciones: 

    a) z^3 - 1   = 0
    b) z^4 - 16 = 0,
    c) z^5 - 32 = 0,
    
expresando el resultado en forma polar y binómica.

/* RESPUESTA EJERCICIO 4 */;

FUNCIONES DE VARIABLE COMPLEJA:

Podemos usar las funciones definidas en MAXIMA para funciones reales sobre números complejos sin necesidad 
de hacer ningún cambio. Por ejemplo, podemos calcular la exponencial de z1=1-i (es decir, e^z1):

z1: 1-%i;
ez1 : exp(z1);
rectform(ez1);

o el logaritmo principal de z1

log(z1);
rectform(%);

Podemos calcular senos y cosenos de z1

cos(z1);
rectform(%);

sin(z1);
rectform(%);

Si preferimos la notación exponencial, usaremos la función

            exponentialize()

para escribir todo en terminos de exponenciales:

exponentialize(cos(z1));

y usaremos 

            demoivre()

para usar senos y cosenos en la salida en lugar de las exponenciales:

demoivre(cos(z1));

Definición de funciones:

Las definiciones de funciones complejas de variable compleja se hacen del mismo modo que las correspondientes a las funciones 
reales, mediante la instrucción

            f(z) := expresión en z,

como por ejemplo, la función z*exp(z) será

f(z):=z*exp(z);

que puede emplearse tanto para reales

f1 : f(2);

como para complejos

f2: f(1+%i);
rectform(f2);

Para encontrar la expresión de una función compleja en términos de su parte real (u) y
su parte imaginaria (v), utilizaremos la variable z en forma binómica, para ello debemos 
definirla como

z:x+%i*y

para evitar duplicidades y errores, borraremos a continuación toda la memoria de MAXIMA

kill(all)$

A continuación definimos la variable z en forma binómica

z:x+%i*y;

A continuación definimos la función

f(z):=z*exp(z);

Y encontramos la parte real (u) y la parte imaginaria (v) con las funciones realpart e imagpart que 
hemos definido al principio:

u: realpart(f(z));
v: imagpart(f(z));

EJERCICIO 5: Encuentra la parte real e imaginaria de las siguientes funciones
   a ) tan(z)
   b) sen(z)
   c) cos(z)
   d) z*exp(-z^2)

/* RESPUESTA EJERCICIO 5 */;

## Análisis Complejo II: Ecuaciones en C.

En esta sección resolveremos ecuaciones y sistemas de ecuaciones en el cuerpo de los números complejos.

Primero borramos todas las variables que hemos usado anteriormente con el fin de no tener problemas.

kill(all)$

Si sólo queremos borrar las variables, dejando las funciones intactas utilizamos la función

remvalue(all);

En MAXIMA, una ecuación es una igualdad entre dos expresiones 
algebraicas escrita con el símbolo =.

3*z^2+2*z+z^3-z^2=4*z^2;

Podemos asignarle un nombre para referirnos a esa ecuación:

mi_ecuación:3*z^2+2*z+z^3-z^2=4*z^2;

lo que nos permite operar con ella:

mi_ecuación*4-3*z^3;

### Resolucion de ecuaciones y sistemas.

MAXIMA puede resolver los tipos mas comúnes de ecuaciones y sistemas de ecuaciones algebráicas de forma exacta. 
Por ejemplo, puede encontrar las raíces de polinomios de grado bajo (2,3 y 4). 

En cuanto a polinomios de grado más alto o ecuaciónes más complicadas, no siempre será posible
encontrar la solución exacta. En este caso, podemos intentar encontrar una solución aproximada.

La orden 

            solve

nos da todas las soluciones, ya sean reales o complejas de una ecuación sistema de ecuaciones:

solve(z^2-3*z+1=0,z);

Si asignamos un nombre a una ecuación, también podemos utilizar dicho nombre para resolverla

ecuacion:z^2-3*z+1=0;
solve(ecuacion);

También podemos resolver ecuaciones que dependan de algún parámetro. En el siguiente ejemplo
usamos el parámetro a dentro de la ecuación.

solve(z^3-a*z^2-z^2+2*z=0,z);

Para obtener la multiplicidad de las raíces se utiliza la función

            multiplicities

solve(z^7-2*z^6+2*z^5-2*z^4+z^3=0);

multiplicities;

La orden solve no sólo puede resolver ecuaciones algebráicas:

solve(sin(z)*cos(z)=0,z);

Vemos, sin embargo, que la instrucción solve no devuelve todas las funciones; ya que 
en este caso, por la periodicidad de las funciones sin(z) y cos(z), las soluciones serían

z_k   =  k*π (raíces de sin(z))

w_k  = (2K+1) π/2 (raíces de cos(z))

Como cualquiera puede imaginarse, MAXIMA no resuelve todo. Incluso en las ecuaciones más “sencillas”, 
los polinomios, se presenta el primer problema: no hay una fórmula en términos algebráicos para obtener 
las raíces de un polinomio de grado 5 o más. 

Pero no hay que ir tan lejos. Cuando añadimos raíces, logaritmos, exponenciales, etc., la resolución de ecuaciones 
se complica mucho. En esas ocasiones lo más que podemos hacer es ayudar a MAXIMA a resolverlas.

Por ejemplo, la ecuación 

z+3 = √(z+1)

no puede resolverse de forma directa

eq:z+3=sqrt(z+1);
solve(eq,z);

Pero se transforma en una ecuación de segundo grado si elevamos al cuadrado ambos miembros de la 
ecuación

(z+3)^2 = (√(z+1))^2

z^2 + 6z + 9 = z+1

z^2 + 5z + 8 = 0

que se resuelve fácilmente con la consabida fórmula de segundo grado.

Con MAXIMA podemos hacerlo todo directamente con la instrucción

solve(eq^2);

donde

eq^2;

También podemos resolver sistemas de ecuaciones. Sólo tenemos que 
escribir la lista de ecuaciónes y de incognitas como
 
solve([ec1, ec2, ec3,.....], [var1, var2, var3, ....]);

donde ec1, ec2, ec3,.... son las ecuaciones del sistema, mientras que var1, var2, var3,.... son
las incógnitas.

Por ejemplo:

solve([x^2+y^2=1,(x-2)^2+(y-1)^2=4],[x,y]);

Si la solucion dependiera de un parametro o de varios, MAXIMA utilizará las variables

                %r1, %r2,... 

para refererirse a estos. Por ejemplo,

solve([x+y+z=3,x-y=z],[x,y,z]);

¿Qué pasa si el sistema de ecuaciones no tiene solución? Veamos 
un ejemplo:

solve([x+y=0,x+y=1],[x,y]);

### Resolucion aproximada de ecuaciónes polinomicas.

Las ecuaciones polinómicas se pueden resolver de manera aproximada (numérica). Para ello podemos
utilizar el comando

            allroots

que nos proporciona todas las raíces del polinomio y

            realroots

que sólo nos da las raíces reales.

Por ejemplo:

eq:x^9+x^7-x^4+x$
allroots(eq);

y si sólo nos interesan las que son reales:

realroots(eq);

EJERCICIO 6: Resuelve las siguientes ecuaciones indicando la multiplicidad de sus soluciones
   a ) z^2 - 2(2-i)z+3(1-2i) = 0
   b) (z+2)(z^2+2z+2) = 0
   c) (z^2+1)(z-3) = 0

Compara las soluciones con las obtenidas por los comando allroots y realroots.

/* RESPUESTA EJERCICIO 6 */;

## Analisis Complejo II: Funciones analíticas.Ecuaciones de Cauchy-Riemann.

LÍMITES:

Con MAXIMA podemos calcular directamente algunos límites de funciones complejas. En concreto, vamos a poder resolver límites
siempre que la función venga dada en terminos de z y la misma sea analítica, en este caso usamos, básicamente, los mismos
procesos que en el caso de funciones con una variable.

Así, vamos a poder calcular límites de la forma siguiente 

remvalue(all);

EJEMPLO 1: Calcular los siguientes límites:

limit(z/(z+1), z, 1);

limit((%i*z+3)/(z+1), z, -1);

NOTA: Para el caso que no exista el límite, o también siempre que la variable z venga expresada en términos de x+%iy, sera más
aconsejable expresar la función f(z) en la forma

f(z)=u(x,y)+%iv(x,y)

y calcular (como límites de funciones de dos variables) tanto el límite de u(x,y) como el de v(x,y). Lo vemos en el siguiente ejemplo:

EJEMPLO 2: Calcula el siguiente límite:

limit((conjugate(z)+%i*z^2)/cabs(z), z, 0);

Observamos que nos da un mensaje de error ya que limit es una funcion 
de una sola variable, y en este caso, al llevar la funcion de la que se
quiere calcular su límite tanto un conjugado como un valor absoluto 
(módulo), esta no va a ser analítica, por lo que para obtener su
límite tendremos que expresarla como dos funciones de dos variables
reales (parte real u(x,y) y parte imaginaria v(x,y)):

z:x+%i*y;

(conjugate(z)+%i*z^2)/cabs(z);

expand(%);

f:rectform(%);

Elegimos la parte real u(x,y) y la parte imaginaria v(x,y):

u:realpart(f);

v:imagpart(f);

Entonces usando las técnicas de cálculo de límites dobles estudiadas
en 1er curso, podremos probar la no existencia de los límites de u(x,y)
y/o v(x,y) (a traves de límites direccionales o mediante un cambio a
polares). También puede verse como hacerlo con wxMAXIMA en la página 
111 del manual que se encuentra en la web:
http://es.scribd.com/doc/52510808/Manual-wxMAXIMA

1er límite iterado

assume(y>0);
limit(limit(u,x,0),y,0);
forget(y>0);

assume(y<0);
limit(limit(u,x,0),y,0);
forget(y<0);

2º límite iterado

assume(x>0);
limit(limit(u,y,0),x,0);
forget(x>0);

assume(x<0);
limit(limit(u,y,0),x,0);
forget(x<0);

ECUACIONES DE CAUCHY-RIEMANN:

Con MAXIMA también podemos estudiar en qué puntos del plano complejo una función 
compleja de variable compleja es derivable, ya que básicamente consiste en encontrar los puntos donde 
se cumplen las ecuaciones de Cauchy-Riemann:

            u_x = v_y

            u_y = -v_x

que constituyen un sistema no lineal de dos ecuaciones y dos incógnitas, que podemos resolver
 con el comando solve.

Vamos a estudiar los puntos de derivabilidad de la función  f(z) = |z|^2. 

Borramos la memoria de MAXIMA, definimos z en forma binómica y la función fz como el módulo al cuadrado de z:

kill(all);
z:x+%i*y;
fz: cabs(z)^2;

Calculamos la parte real e imaginaria de la función

u:realpart(fz);
v:imagpart(fz);

Calculamos las derivadas parciales de u: du/dx y du/dy

ux: diff(u,x);
uy: diff(u,y);

Calculamos las derivadas parciales de v: dv/dx y dv/dy

vx: diff(v,x);
vy: diff(v,y);

Planteamos las dos ecuaciones de Cauchy Riemann

Primera ecuación de Cauchy-Riemann: du/dx = dv/dy

ecr1 : ux = vy;

Segunda ecuación de Cauchy-Riemann: du/dy = -dv/dx

ecr2 : uy = -vx;

Resolvemos el sistema para encontrar los puntos donde se cumplen
las dos ecuaciones de forma simultánea.

solve([ecr1,ecr2],[x,y]);

Observamos que no se verifican las ecuaciónes de C-R salvo si x=y=0.
Por tanto, f'(z) no existe salvo si z=0.

La derivada de la función en este punto se puede calcular mediante la expresión 

f'(z) = u_x + i v_x

derivada: ux+%i*vx;
derivada_en_0 : ux+%i*vx,x=0,y=0;

Si por ejemplo estudiáramos la derivabilidad de una función entera como f(z)=exp(z), el proceso
sería el mismo:

fz: exp(z);
rectform(fz);

Parte real e imaginaria:

u:realpart(fz);
v:imagpart(fz);

Derivadas parciales de u:

ux : diff(u,x);
uy : diff(u,y);

Derivadas parciales de v:

vx: diff(v,x);
vy: diff(v,y);

Ecuaciones de Cauchy-Riemann:

ecr1 : ux = vy;
ecr2 : uy = -vx;

Soluciones al sistema de Cauchy-Riemann

solve([ecr1,ecr2],[x,y]);

Observamos que las soluciones vienen dadas en términos de dos parámetros independientes: %r1 y %r2, 
esto indica que las ecuaciónes de Cauchy-Riemann se cumplen para cualquier valor de x e y, lo que hace que 
la función fz =exp(z) sea derivable en todo z y por tanto entera.

Para el cálculo de la derivada  f'(z)= diff(u,x)+%i*diff(v,x):

derivada_f:ux + %i*vx,x=x,y=y;

Hemos llegado al conocido resultado de que si f(z)=exp(z), entonces f'(z)=f(z). 
A esta misma conclusión se puede llegar si hubiesemos usado la función

            diff( funcion, variable)

remvalue(all);
diff(exp(z),z);

Aquí hemos calculado una derivada como si la función a derivar no fuese compleja, sino que fuese
una función con una sola variable. Esto siempre puede hacerse en  caso que la función a derivar sea analítica, 
mientras que si no lo es (porque, por ejemplo, lleve un módulo o un conjugado en su definición) no lo vamos 
a poder hacer y tendremos que usar la expresión correspondiente(como hemos visto en el ejemplo anterior).

FUNCIONES ARMÓNICAS:

Otro típico ejercicio de variable compleja relacionado con la derivación consiste en, dada la parte real u(x,y) de una función analítica, hallar 
su función armónica conjugada, es decir, otra función v(x,y) tal que la función dada por f(z)=u(x,y)+iv(x,y) sea analítica. 

Lo vemos en el siguiente ejemplo.

Dada la función u(x,y)=3*x^2*y+2*x^2-y^3-2*y^2, probar que es armónica y hallar su armónica conjugada:

u: 3*x^2*y+2*x^2-y^3-2*y^2;

Será armónica si cumple la ecuación de Laplace: u_xx + u_yy = 0

diff(u,x,2)+diff(u,y,2);

Como este último resultado da 0, u(x,y) es armónica y podremos encontrar su armónica conjugada.

Para hallar la armónica conjugada, se utilizarán las ecuaciones de Cauchy-Rimeann. 

Primera Ecuación: Como 

u_x = v_y

entonces, integrando respecto de y obtendremos la expresión de v

v = ∫u_x dx

u_x: diff(u,x);

v: integrate(u_x, y);

Notar que no se incluye la constante de integración, que como se ha explicado en clase debe ser constante respecto a y, pero no tiene 
porque ser constante respecto a x, así que supondremos que es una función g(x)

vtemp: v+g(x);

Segunda ecuación: Usaremos la segunda de las condiciones de Cauchy-Riemann para calcular g(x). 

Se tiene que u_y = -v_x, así que calculamos por una parte v_x, derivando respecto de x el último resultado 
obtenido y por otra u_y

u_y: diff(u,y);
v_x: diff(vtemp,x);

Planteamos la segunda ecuación de Cauchy-Riemann

ecr2 : u_y = -v_x;

Despejamos g'(x) 

solucion: solve(ecr2,'diff(g(x),x,1));

E integramos para encontrar g(x)

g: integrate(rhs(solucion[1]),x);

Le incorporamos la constante de integración

g: g + k;

Finalmente la función v será:

v: v+g;

La función f 

powerdisp: true $
f : u + %i*v;

Y la función f(z) se obtiene al sustituir en la expresión anterior x por z e y por 0

f,x=z,y=0;

EJERCICIO 7: Estudia los puntos donde las siguientes funciones son derivables y calcula en ellos la derivada correspondiente:

    a) f(z) = (~z)*Imag(z)
    b) f(z) = xy + iy
    c) f(z) = 3x + y + i(3y-x)


EJERCICIO 8: Comprueba que las siguentes funciones son armónicas, encuentra sus armónicas conjugadas y expresa las correspondientes 
funciones f(x+iy) como funciones f(z).

   a) u(x,y) = x/(x^2+y^2)
   b) u(x,y) = x^2 - y^2 + 2xy - x + 3
   c) u(x,y) = atan(y/x)