viernes, 11 de mayo de 2018

Aprendiendo convoluciones

La convolución es una operación matemática  que se aplica a dos funciones (en $L^p$)en donde se obtiene como resultado el valor de solapamiento de una función respecto a la otra.
$$ u*v (t)= \int_{\mathbb{R} } u(x)v(t-x) dx$$

Esta operación matemática, nos genera una función continua cuando alguna de las funciones está acotada.Se le llama kernel o filtro a una función fija($v$) que se convoluciona con la función variable($u$) para obtener características(en procesamiento de señales se llama respuesta al impulso) de $u$ respecto al filtro $g$.

En aprendizaje automático se requieren describir el objeto que queremos clasificar (algún tipo de señal como un audio o imagen) mediante sus características para luego proceder a usar algún algoritmo de clasificación(redes neuronales o SVM).


En aprendizaje profundo, estás características que describen al objeto son aprendidas automáticamente mediante algún algoritmo de optimización(gradiente descendiente o adam optimizer). Una de las redes más populares son las redes neuronales convolucionales (CNN), que utilizan el concepto de convolución para ir obteniendo características del objeto para su descripción.

Vamos a ver su parte computacional en Python3 para entender con ejemplos este concepto:

Sean $u$ y $v$ vectores , el producto de convolucíon es:
$$ (u*v)[i] = \sum_{j=0}^{\infty}  u[j]v[i-j] = \sum_{s+t=i} u[s]v[t] $$

ejemplo: 
Sea $u = [2, 5, 0, 4]$ y $v = [4, 1, 3]$
Si decimos que $v$ es el filtro, entonces haremos un barrido del filtro para recoger características de $u$

Para hacer el barrido en los bordes se debe completar con ceros el vectocon el filtro al revés $u$
Sean los indices:
$$ u=[u[0],u[1],u[2],u[3]] $$
$$ v=[v[0],v[1],v[2]] $$

$$ (u*v)[0] = \sum_{j=0}^{\infty} u[j][0-j] = u[0]v[0] + u[1]v[-1] + u[2]v[-2]+ u[3]v[-3] + ... = u[0]v[0] = 8 $$

debido a que los indices $-1,-2,-3$  no están definidos, lo podemos definir con ceros ,y así en los démas casos

$$ u[5] =0 , v[-1] = 0, u[-8] = 0, ... etc $$

De igual forma con los demás términos
$$ (u*v)[1] = \sum_{j=0}^{\infty} u[j][1-j] =u[0]v[1] + u[1]v[0] +... = 22 $$
$$ (u*v)[2] = \sum_{j=0}^{\infty} u[j][2-j] =u[0]v[2] + u[1]v[1] + u[2]v[0]... = 11 $$
$$ (u*v)[3] = \sum_{j=0}^{\infty} u[j][3-j] =u[0]v[3] + u[1]v[2] + u[2]v[1]+ u[3]v[0] =31$$
$$ (u*v)[4] = \sum_{j=0}^{\infty} u[j][3-j] =u[0]v[4] + u[1]v[3] + u[2]v[2]+ u[3]v[1] =4$$
$$ (u*v)[5] = \sum_{j=0}^{\infty} u[j][3-j] =u[0]v[5] + u[1]v[4] + u[2]v[3]+ u[3]v[2] =12$$


# Definimos los vectores
u = [2, 5, 0, 4]  #vector de entrada
v = [4, 1, 3]   #filtro
print(u)
print(v)
[2, 5, 0, 4]
[4, 1, 3]

conv = []  
for j in range(len(u)+len(v)-1):
    suma = 0
    for i in range(len(u)):
        if (j-i)>=0 and (j-i)<len(v):
            suma = u[i]*v[j-i] + suma
    conv.append(suma)
conv
[8, 22, 11, 31, 4, 12]

Podemos agruparlo en una función.
# Función de convolución
def convolucion(u,v):
    conv = []
    m = len(u)
    n = len(v)
    for j in range(m+n-1):  #m+n-1 es el tamaño de la convolucion
        suma = 0
        for i in range(m):
            if (j-i)>=0 and (j-i)<n:
                suma = u[i]*v[j-i] + suma
        conv.append(suma)
    return conv

print(convolucion(u,v))
[8, 22, 11, 31, 4, 12]

Usando Numpy

En numpy , ya se obtiene está función con el comando convolve Esta función es un poco más rapido
import numpy as np
print(np.convolve(u,v))  #se obtiene el mismo resultado
[ 8 22 11 31  4 12]

Usando Scipy

from scipy import signal
signal.convolve(u,v)
array([ 8, 22, 11, 31,  4, 12])


Usando el mismo concepto se puede extender a n-dimensiones.
Este concepto de convoluciones explica las funciones waveletes que tienen un mayor concepto en las matemáticas.


jueves, 22 de diciembre de 2016

Simulación Numérica en Matlab para el modelo de Infiltración 1D

Realizaremos la simulación de Infiltración en un medio poroso y tomaremos como referencia a dos papers: el de Kumar y el de Celia de 1990.

Ecuación general de flujo no saturado

El flujo en zonas saturadas indica que cuando se alcanza una cierta zona(llamada zona saturada), la humedad es constante, así no habría nada que modelar en ese caso.

De acuerdo con la ley de Darcy, para una dimensión de flujo vertical, el volumen de flujo q(cm^3/cm^3/h) puede ser escrito como

$$q = -K \frac{\partial }{\partial z}(h-z) =-K (\frac{\partial h}{\partial z}-1)  $$
Donde K es la conductividad hiráulica(cm/h), "h" es la presión de agua en el suelo(relativo a la atmósfera) expresado en cm de agua y "z" es la componente vertical considerado positivo cuando va hacia abajo.

Del paper obtenemos las ecuaciones a usar:
$$ C = \frac{\mathrm{d} \theta}{\mathrm{d} h} $$
$$C(h) \frac{\partial h}{\partial t} = \frac{\partial }{\partial z} [K(h) (\frac{\partial h}{\partial z}-1)]$$
La funcion theta indica la humedad para una profundidad y tiempo dado.
Para el estudio, las condiciones iniciales son definidas como
$$\theta (z, t=0) = 0.1$$
$$\theta (z=0, t) = 0.267$$
La primera condición indica que el suelo va estar recibiendo una fuente de fluido constantemente, siempre en z=0(la superficie) se tendra una humedad de 0.267.
La segunda condición indica que inicialmente el suelo estaba casi seco en la zona no saturada.

Simulación

Luego del tiempo 0 empieza la simulación y del paper de Celia(referenciadas al principio) tenemos las siguientes relaciones:
$$K = K_s  \frac{A}{A+ \left | h^{\beta_1} \right |}$$
Donde Ks=34 cm/h, A=1175000, b1 =4.74 y
$$ \theta = \frac{\alpha (\theta_s \theta_r)}{\alpha+ \left | h^{\beta_2} \right |}+\theta_r$$
Donde theta_s =0.287, theta_r = 0.075, alfa = 1611000, b2 = 3.96.

Usando diferencias finitas

$$ C_i^{j+a} \frac{h_i^{j+1} -h_i^j}{\Delta t} = \frac{1}{\Delta z}\left [
 K_{i+1/2}^{j+a}\left (\frac{h_{i+1}^{j+a} -h_i^{j+a}}{\Delta z} -1\right )-
K_{i-1/2}^{j+a}\left ( \frac{h_{i}^{j+a} -h_{i-1}^{j+a}}{\Delta z} -1\right ) \right ]   $$

Donde "a" es un factor de peso entre 0 y 1, siendo a = 0 el esquema explicito, a = 0.5 el esquema de Crank - Nicolson y a = 1 el esquema implicito.

Ejemplo con 41 nodos de profundidad (0-40)

Si se desea el esquema explicito (a = 0), se puede emplear simplemente el siguiente código:

thetaS = 0.287; thetaR = 0.075; alfa = 1.611e6;
beta2 = 3.96;
tf = @(h) (alfa.*(thetaS-thetaR))./(alfa+(abs(h)).^beta2) + thetaR;
Ks = 0.00944; Ar = 1.175e6; beta1 = 4.74; %Ks debe estar en cm/s
kf = @(h) Ks.*Ar./(Ar+ abs(h).^beta1);
cf =@(h) -alfa*beta2*(thetaS-thetaR)*sign(h).*abs(h).^(beta2-1)./(alfa+abs(h).^beta2).^2;
hf =@(t) abs(alfa.*(thetaS-t)./(t-thetaR)).^(1/beta2);

z_max = 40;
n=40; T=360; dz=z_max/n; dt=0.4;
t=0.1*ones(1,n);
h = -hf(t);
h(1) = -hf(0.267);
h(n) = -hf(0.1);
k=kf(h);
c =cf(h);
temp = h;

for j=1:dt:T
    for i=2:n-1
        temp(i) = h(i)+dt/dz/c(i)*(sqrt(k(i)*k(i+1))*((h(i+1)-h(i))/dz -1)...
        - sqrt(k(i-1)*k(i))*((h(i)-h(i-1))/dz -1));
    end
    h = temp;
    k = kf(h);
    c = cf(h);
end
z=0:n-1;
plot(z,h,'k');

Los valores de c y de k se aproximan mediante:
$$ C_i^{j+a} = F_1 = (1-a)C_i^j + a C_i^{j+1}$$
$$ K_{i+1/2}^{j+a} = F_2 = (1-a)K_{i+1/2}^j + a K_{i+1/2}^{j+1}= (1-a)\sqrt{K_i^j K_{i+1}^j} +a\sqrt{K_i^{j+1} K_{i+1}^{j+1}}$$
$$ K_{i-1/2}^{j+a} = F_3 = (1-a)K_{i-1/2}^j + a K_{i-1/2}^{j+1}= (1-a)\sqrt{K_{i-1}^j K_{i}^j} +a\sqrt{K_{i-1}^{j+1} K_{i}^{j+1}}$$


Acomodando la ecuación para poder formar un sistema lineal
$$\left [ -aF_3 \frac{\Delta t}{(\Delta z)^2} \right ] h_{i-1}^{j+1}+
\left [ F_1+aF_2 \frac{\Delta t}{(\Delta z)^2}+aF_3 \frac{\Delta t}{(\Delta z)^2} \right ] h_{i}^{j+1}+
\left [ -aF_2 \frac{\Delta t}{(\Delta z)^2} \right ] h_{i+1}^{j+1}$$

$$ =
\left [ (1-a)F_3 \frac{\Delta t}{(\Delta z)^2} \right ] h_{i-1}^{j}+
\left [ F_1-(1-a)F_2 \frac{\Delta t}{(\Delta z)^2}-(1-a)F_3 \frac{\Delta t}{(\Delta z)^2} \right ] h_{i}^{j}+
\left [ (1-a)F_2 \frac{\Delta t}{(\Delta z)^2} \right ] h_{i+1}^{j}+
(F_3 - F_2)\frac{\Delta t}{\Delta z} $$

Tenemos que resolver el siguiente sistema lineal

$$\begin{bmatrix}
F_1^1+aF_2^1 \frac{\Delta t}{(\Delta z)^2}+aF_3^1 \frac{\Delta t}{(\Delta z)^2}  &  -aF_2^1 \frac{\Delta t}{(\Delta z)^2} & 0 & \cdots  & 0\\
 -aF_3^2 \frac{\Delta t}{(\Delta z)^2}& F_1^2+aF_2^2 \frac{\Delta t}{(\Delta z)^2}+aF_3^2 \frac{\Delta t}{(\Delta z)^2} & -aF_2^2 \frac{\Delta t}{(\Delta z)^2} & \cdots  & 0\\
 &  &  &  & \\
 \vdots & \ddots  & \ddots  & \ddots  & \vdots \\
 0& \cdots  & 0 & -aF_3^{39} \frac{\Delta t}{(\Delta z)^2} & F_1^{39}+aF_2^{39} \frac{\Delta t}{(\Delta z)^2}+aF_3^{39} \frac{\Delta t}{(\Delta z)^2}
\end{bmatrix}
\begin{bmatrix}
h_{1}^{j+1}\\
 h_{2}^{j+1}\\
h_{3}^{j+1}\\
\vdots \\
h_{39}^{j+1}
\end{bmatrix}$$

$$ = $$

$$\begin{bmatrix}
F_1^1-(1-a)F_2^1 \frac{\Delta t}{(\Delta z)^2}-(1-a)F_3^1 \frac{\Delta t}{(\Delta z)^2}  &(1-a)F_2^1 \frac{\Delta t}{(\Delta z)^2} & 0 & \cdots  & 0\\
 (1-a)F_3^2 \frac{\Delta t}{(\Delta z)^2}& F_1^2-(1-a)F_2^2 \frac{\Delta t}{(\Delta z)^2}-(1-a)F_3^2 \frac{\Delta t}{(\Delta z)^2} & (1-a)F_2^2 \frac{\Delta t}{(\Delta z)^2} & \cdots  & 0\\
 &  &  &  & \\
 \vdots & \ddots  & \ddots  & \ddots  & \vdots \\
 0& \cdots  & 0 & (1-a)F_3^{39} \frac{\Delta t}{(\Delta z)^2} & F_1^{39}-(1-a)F_2^{39} \frac{\Delta t}{(\Delta z)^2}-(1-a)F_3^{39} \frac{\Delta t}{(\Delta z)^2}
\end{bmatrix}
\begin{bmatrix}
h_{1}^{j}+(F_3^1 - F_2^1)\frac{\Delta t}{\Delta z}+aF_3^1 \frac{\Delta t}{(\Delta z)^2} h_0^{j+1} + (1-a)F_3^1 \frac{\Delta t}{(\Delta z)^2} h_0^{j} \\
 h_{2}^{j}\\
h_{3}^{j}\\
\vdots \\
h_{39}^{j}+(F_3^{39} - F_2^{39})\frac{\Delta t}{\Delta z}+aF_3^{39} \frac{\Delta t}{(\Delta z)^2} h_{40}^{j+1} + (1-a)F_3^{39} \frac{\Delta t}{(\Delta z)^2} h_{40}^{j}
\end{bmatrix}$$
Valido para j = 0,1, ... , M , M es un número natural tal que dt = T/M(puede ser igual o redondearse al mínimo entero).

El código general es el siguiente, agrupe los términos por comodidad en t1,t2,t3 y ti(término independiente).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
%   Solucón Numérica para la ecuacuón de Richards
%    Infiltración de líquido en medio poroso
%    
%
%
%
% Forma general
tic ();
thetaS = 0.287; thetaR = 0.075; alfa = 1.611e6;
beta2 = 3.96;
tf = @(h) (alfa.*(thetaS-thetaR))./(alfa+(abs(h)).^beta2) + thetaR;
Ks = 0.00944; Ar = 1.175e6; beta1 = 4.74; %Ks debe estar en cm/s
kf = @(h) Ks.*Ar./(Ar+ abs(h).^beta1);
cf =@(h) -alfa*beta2*(thetaS-thetaR)*sign(h).*abs(h).^(beta2-1)./(alfa+abs(h).^beta2).^2;

hf =@(t) abs(alfa.*(thetaS-t)./(t-thetaR)).^(1/beta2);
z_max = 40;
n=z_max; T=300; dz=z_max/n; dt=0.4;
a = 0.5; 
u=dt/dz^2;
t=0.1*ones(1,n);
h = -hf(t);
h(1) = -hf(0.267);
h(n) = -hf(0.1);
k=kf(h);
c =cf(h); 
hj1 = h;
cj1=c;
kj1 = k;
temp = h; 

for j=1:dt:360
    %PREDICTOR
    for i=2:n-1
        temp(i) = h(i)+dt/dz/c(i)*(sqrt(k(i)*k(i+1))*((h(i+1)-h(i))/dz -1)...
        - sqrt(k(i-1)*k(i))*((h(i)-h(i-1))/dz -1));
    end
    hj1 = temp;
    kj1 = kf(hj1);
    cj1 = cf(hj1);
   %CORRECTOR
    for i=2:n-1
        f1(i-1) = (1-a)*c(i)+a*cj1(i);
        f2(i-1) = (1-a)*sqrt(k(i)*k(i+1))+a*sqrt(kj1(i)*kj1(i+1));
        f3(i-1) = (1-a)*sqrt(k(i)*k(i-1))+a*sqrt(kj1(i)*kj1(i-1));
        t1(i-1) = -a*u*f3(i-1);
        t2(i-1) = f1(i-1)+a*u*f2(i-1)+a*u*f3(i-1);
        t3(i-1) = -a*u*f2(i-1);
        t1b(i-1) = (1-a)*u*f3(i-1);
        t2b(i-1) = f1(i-1)-(1-a)*u*f2(i-1)-(1-a)*u*f3(i-1);
        t3b(i-1) = (1-a)*u*f2(i-1);
        ti(i-1) = dt/dz*(f3(i-1)-f2(i-1));
    end
    ti(1) = ti(1) - t1(1)*h(1)+t1b(1)*h(1);
    ti(n-2) = ti(n-2) - t3(n-2)*h(n)+t3b(n-2)*h(n);
    B=diag(t1b(2:end),-1)+diag(t2b)+...
    diag(t3b(1:n-3),+1);
    A=diag(t1(2:end),-1)+diag(t2)+...
    diag(t3(1:n-3),+1);
    b = ti;
    x0 = h(2:n-1);
    h(2:n-1) = A\(B*x0'+b');
    k = kf(h);
    c = cf(h);
    temp = h;
end

z=0:n-1;
elapsed_time = toc ();
fprintf('se demoro %4.4f segundos \n',elapsed_time);
plot(z,h,'r');

Este ejemplo esta con el esquema de Crank Nickolson (a = 0.5), puedes modificar haciendo varia el "a", "dt", "T", "n", "dz", consultar las referencias para ver los valores de convergencia.

Muestra para T=360, T=720 y T= 0.8 horas = 8 x 360 s




Muestra de los esquemas para dt = 0.4, T=360, n=40 y valores de a entre 0 y 1.
Casi no se nota la diferencia.


Para dt = 3 , se ve cuando a< 0.5 diverge y cuando es mayor converge.

Continuaré en otro post, espero haberles ayudado ;)

domingo, 26 de julio de 2015

RNA - Aprender un numero digital

RNA - Aprender un numero digital

Con la plantilla utilizada para construir una red neuronal de la entrada anterior, la modificaremos  para el siguiente modelo:
Ahora la capa "K" tiene 4 nodos(neuronas) con 5 entradas más una entrada del Bias(entrada de otra neurona como parte de una red) , así tendría 6 entradas para cada nodo "K". Para la capa "J" tenemos 5 nodos con 7 entradas más una entrada como "bias" , lo que suma 8 entradas para cada nodo de la capa "J".

                   Numero        Representación digital          Representación Binaria
                      0                      1  1  1  0  1  1  1                        0  0  0  0  0
                      1                      1  0  0  0  0  0  1                        0  0  0  0  1
                      2                      1  1  0  1  1  1  0                        0  0  0  1  0
                      3                      1  1  0  1  0  1  1                        0  0  0  1  1
                      4                      1  0  1  1  0  0  1                        0  0  1  0  0
                      5                      0  1  1  1  0  1  1                        0  0  1  0  1
                      6                      0  1  1  1  1  1  1                        0  0  1  1  0
                      7                      1  1  0  0  0  0  1                        0  0  1  1  1
                      8                      1  1  1  1  1  1  1                        1  0  0  0  0
                      9                      1  1  1  1  0  1  1                        1  0  0  0  1

La representación digital serán la entradas junto a un balance del "bias"(en este caso -1) y la representación binaria es lo que la red debe aprender



public class TestNumero {                            //NK NJ EK EJ
    static RedNeuronal1 redNeuronal = new RedNeuronal1( 4, 5, 6, 8);
    static double balance = -1;                      
    static double[][] capaI = {{1,1,1,0,1,1,1,balance},  //0
                 {1,0,0,0,0,0,1,balance},  //1
                               {1,1,0,1,1,1,0,balance},  //2
                               {1,1,0,1,0,1,1,balance},  //3
       /*rep. digital*/        {1,0,1,1,0,0,1,balance},  //4
                               {0,1,1,1,0,1,1,balance},  //5
                               {0,1,1,1,1,1,1,balance},  //6
                               {1,1,0,0,0,0,1,balance},  //7
                               {1,1,1,1,1,1,1,balance},  //8
                               {1,1,1,1,0,1,1,balance}}; //9
    static double[][]  aprender =  {{0,0,0,0,0,0,0,0,1,1},
        {0,0,0,0,1,1,1,1,0,0},
                                    {0,0,1,1,0,0,1,1,0,0},
                                    {0,1,0,1,0,1,0,1,0,1}}; 
                                  //0  1 2 3 4 5 6 7 8 9    rep. binaria



Descargar archivo con frame para aprender un numero digital.
Descargar plantilla RNA
RNA - Aprender si un cuadrado es par

Definiremos los cuadrados impares, y definiremos a la cantidad impar con el valor de " 0 ".
Solo será par cuando dos casillas estén pintadas y tendrá el valor de " 1 ". No estarán definidas el cuadro sin pintar ni el cuadro con todas las casillas pintadas.


Cada nodo posee un vector de entradas(en este caso son 5 para la capa J y 3 para la capa K), y cada entrada tiene un peso("inicialmente aleatorios") y un función de activación(en este ejemplo sera la funcion sigmoidal).

También para cada nodo tendremos un error , utilizaremos el entrenamiento Backpropagation .






Construimos la clase nodo("neuron1")

package parimparrn;

public class Neuron1 {
    private double activacionu;
 double [] entradas;
 double [] pesos;
 double errorNodo;
 static Sigmoide sigmoide;
        public Neuron1(int nentradas)
 {
  pesos = new double[nentradas];
  entradas = new double[nentradas];
  sigmoide = new Sigmoide();
  errorNodo = 0;
 }
 public void activacion()
 {
  double suma = 0;
  for(int i=0;i<entradas.length;i++)
  {
   suma =suma + entradas[i]*pesos[i];
  }
  activacionu = sigmoide.funcion(suma);
 }

    public double[] getEntradas() {
        return entradas;
    }

    public void setEntradas(double[] entradas) {
        this.entradas = entradas;
    }

    public double[] getPesos() {
        return pesos;
    }

    public void setPesos(double[] pesos) {
        this.pesos = pesos;
    }
 public void verEntradas()
 {
  System.out.print(" entradas  ");
  for(int i=0;i<entradas.length;i++)
  {
   System.out.println(entradas[i]);
  }
 }
 public void verPesos()
 {
  System.out.println(" *** pesos ** ");
  for(int i=0;i<pesos.length;i++)
  {
   System.out.println(""+pesos[i]);
  }
 }
 public double getActivacion()
 {
  return activacionu;
 }
 public void verActivacion()
 {
  System.out.println("activacion");
  System.out.println(""+activacionu);
 }
 public double getError()
 {
  return errorNodo;
 }
 public void setError(double error)
 {
  errorNodo=error;
 }
        
}
Adjunto el proyecto , el archivo con frame , utiliza los pesos aprendidos tras ejecutar el método run de la clase TestRN.En  el proyecto sin frame se ejecuta el método y se encuentra los pesos para la red.
Descargar Proyecto completo con frame
Descargar Proyecto completo sin frame
Descargar  plantillas de RNA

jueves, 2 de julio de 2015

Ecuación de Lorenz


El siguiente sistema , modela el comportamiento de una atmósfera simple.
Para rho<24.75 el sistema es estable,pero para rho>24.75 es impredecible analíticamente.
File en lenguaje Matlab.

1
2
3
4
5
6
7
8
function dx=lorenzatt(T,X)
 rho = 28; sigma = 10;  beta = 8/3;
 dx = zeros(3,1);
 dx(1) = sigma*(X(2) - X(1));
 dx(2) = X(1)*(rho - X(3))-X(2);
 dx(3) = X(1)*X(2) - beta*X(3);
 return
end

Listas palindromas

20.11 Escriba un programa que utilice un objeto pila para determinar si una cadena es una palíndroma (es decir, que la cadena se deletree en forma idéntica, tanto al revés como al derecho). El programa debe ignorar espacios y puntuación.

#include <iostream>
using namespace std;
struct nodo
{
 char dato;
 struct nodo *sig;
};

void inicializar(nodo **cab)
{
 *cab = NULL;
}

void push(nodo **cab , char nuv)
{
 nodo *q;
 q = new nodo;
 q->dato = nuv;
 if(*cab == NULL)
 {
  q->sig = *cab;
  *cab = q;
 }
 else
 {
  q->sig = *cab;
  *cab = q;
 }
}

char pop(nodo **cab)
{
 nodo *aux;
 char num;
 aux = *cab;
 if(aux)
 {
  num = aux->dato;
  *cab = (*cab)->sig;
  delete aux;
  return num;
 }
 else
 {
  return 0;
 }
}

int comparar(nodo *cab, nodo *cab2 , int n)
{
     int b = 1; 
     for(int i=0;i<n;i++)
     {
         if(cab->dato == cab2->dato)
         {
             cab = cab->sig;
             cab2 = cab2->sig;
         }
         else
             b = 0;
     }
     return b;
}

void mostrar(nodo *cab)
{
 while(cab)
 {
  cout<<cab->dato;
  cab = cab->sig;
 }
 cout<<"\n\n\n";
}

int main()
{
 nodo *cab , *cab2;
 inicializar(&cab);
 inicializar(&cab2);
    string palabra ="anita lava la.. tina";
 //cout<<" ingresa palabra:  ";
 //cin>>palabra;
 int cont=0;
 for(int i=(palabra.length()-1);i>=0;i--)
 {
            if(palabra[i] != ' ')
            {     if(palabra[i] != '.')
                    push(&cab , palabra[i]);
                  else
                      cont++;  }
            else
                cont++;
    }
    for(int i=0;i<palabra.length();i++)
 {
            if(palabra[i] != ' ')
            {     if(palabra[i] != '.')
                    push(&cab2 , palabra[i]);
                  else
                      cont++;  }
            else
                cont++;
    }
 cout<<comparar(cab , cab2, palabra.length()-cont)<<" '1 iguales , 0 diferentes'  \n";
    mostrar(cab2);
 mostrar(cab);
 
 system("pause");
 return 0;
}


Invertir lista de caracteres

20.9 Escriba un programa para crear un objeto lista enlazada de 10 caracteres, y que luego cree un segundo objeto lista que contenga una copia de la primera lista, pero en orden inverso.

#include <iostream>
using namespace std;

struct nodo
{
       char info;
       struct nodo *sig;
};

void generarLista(nodo **inicio)
{
     nodo *q , *fin;
     for(int i=0;i<5;i++)
     {
             q = new nodo;
             q->info = (char)(rand()%10+70);
             
             if(*inicio == NULL)
             {
                  q->sig = *inicio;
                  *inicio = q;
                  fin = q;
             }
             else
             {
                 q->sig = fin->sig;
                 fin->sig = q;
                 fin = q;
             }
     }
}
nodo *obtenerFin( nodo *inicio)
{
     while( inicio->sig != NULL )
         inicio=inicio->sig;
     
     return inicio;
}


nodo *EliminarFin( nodo *inicio )
{
     nodo *fin , *aux;
     fin = obtenerFin(inicio);
     aux=inicio;
     
     while( aux->sig != fin )
         aux=aux->sig;
     
     aux->sig= fin->sig;
     
     
     delete fin;
     
     return inicio;
}  

nodo *InsertarFinal( nodo *inicio ,nodo *fin, char nom)
{
     nodo *q ;
     q = new nodo;
     q->info = nom;
     
     
     if(fin==NULL)
     {
         q->sig = inicio;
         inicio  = q;
         fin     = q;        
     }
     else
     {
         q->sig   = fin->sig;
         fin->sig = q;
         fin       = q;
     }
     return inicio;
}    

void mostrar(nodo *inicio)
{
     while(inicio)
     {
          cout<<inicio->info<<"  ";
          inicio = inicio->sig;
     }
     cout<<"\n\n\n";
}

int main()
{
    nodo *inicio , *inicio2 , *fin2;
    inicio  = NULL;
    inicio2 = NULL;
    fin2 = NULL;
    generarLista(&inicio);
    mostrar(inicio);
    
    inicio2 = InsertarFinal(inicio2 ,fin2 , obtenerFin(inicio)->info);
    inicio  = EliminarFin(inicio);
    inicio2 = InsertarFinal(inicio2 ,obtenerFin(inicio2) , obtenerFin(inicio)->info);
    inicio  = EliminarFin(inicio);
    inicio2 = InsertarFinal(inicio2 ,obtenerFin(inicio2) , obtenerFin(inicio)->info);
    inicio  = EliminarFin(inicio);
    inicio2 = InsertarFinal(inicio2 ,obtenerFin(inicio2) , obtenerFin(inicio)->info);
    inicio  = EliminarFin(inicio);
    inicio2 = InsertarFinal(inicio2 ,obtenerFin(inicio2) , obtenerFin(inicio)->info);
    
    mostrar(inicio2);
    
    system("pause");
    return 0;
}