function pme(caso,dim,vetk,simulacoes,it_max,salvar,op_morf)

%
% Probabilidade de Memória Espúria e Número de Iterações
%
% Esta rotina estima a probabilidade de memória espúria e o número de iterações 
% para os modelos de memória associativa auto e hetero-associativas.
%
% Comando: pme(caso,dim,vetk,simulacoes,salvar,op_morf);
%
% Entradas: 
%       Caso - Caso auto-associativo (caso=1) ou caso heteroassociativo (caso=2);
%              Padrão: Caso = 1;
%        dim - Dimensão dos padrões de entrada e saída ;
%              Padrão: dim = [25,20];
%       vetk - Vetor contendo o número de pares de padrões que serão 
%                  armazenados nas memórias associativas (Padrão: vetk = [1:n]);
% simulacoes - Número de simulações (Padrão: simulacoes = 100)
%     it_max - Número máximo de iterações dos modelos dinâmicos (Padrão: it_max=max(n,m)); 
%     salvar - Salva os resultados nos arquivos pme_auto.mat e it_auto.mat 
%                ou pme_hetero.mat e it_hetero.mat quando salvar=1 (padrão: salvar=1);
%    op_morf - Impõe X(:,1)=zeros(n,1) ou X(:,1)=ones(n,1) nas memórias 
%                associativas morfológicas quando op_morf=1 (Padrão: op_morf=1)
%

if nargin<7
   op_morf=1;
end

if nargin<6
   salvar=1;
end

if nargin<4
   simulacoes=100;
end

if nargin<2
   dim = [25,20];
end

if nargin<5
   it_max=max(dim);
end

if nargin<3
   vetk=[1:dim(1)];
end

if nargin<1
   caso=1;
end

n=dim(1);
if length(dim)<2
   m=dim(1);
else
   m=dim(2);
end

if length(vetk)==1
   vetk(2)=vetk(1);
end

k_leng=length(vetk);

if caso==1
   % Variáveis do caso Auto-associativo
   pme_hopfield=zeros(k_leng,1);
	it_hopfield=zeros(k_leng,1);

	pme_personnaz=zeros(k_leng,1);
	it_personnaz=zeros(k_leng,1);

	pme_kanter=zeros(k_leng,1);
	it_kanter=zeros(k_leng,1);

	pme_ecam=zeros(k_leng,1);
	it_ecam=zeros(k_leng,1);

	pme_Wxx=zeros(k_leng,1);
   pme_mam2c1=zeros(k_leng,1);
end

if caso==2
   % Variáveis do caso Heteroassociativo
   pme_bam=zeros(k_leng,1);
	it_bam=zeros(k_leng,1);

	pme_abam=zeros(k_leng,1);
	it_abam=zeros(k_leng,1);

	pme_becam=zeros(k_leng,1);
	it_becam=zeros(k_leng,1);

	pme_Wxy=zeros(k_leng,1);
   pme_mam2c2=zeros(k_leng,1);
end

for s=1:simulacoes
   tic
   for xi=1:k_leng
      % Gerando a matriz contendo as memórias fundametais;
      X=sign(2*rand(n,vetk(xi))-1);
      % Gerando o padrão-chave
      xin=sign(2*rand(n,1)-1);
      
      if caso==1
          %
          % Caso Auto-Associativo;
          %
          
          %
          % Memória Associativa de Hopfield;
          %
          
          % Fase de armazenamento:
          clear W; W=corr0(X);        
          % Fase de Recordação;
          clear xout; clear it;
          [xout,it]=mad(W,xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(X'*xout)/n)<1;
             pme_hopfield(xi)=pme_hopfield(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_hopfield(xi)=it_hopfield(xi)+it;
          
          %
          % Memória Associativa de Personnaz;
          %
          
          % Fase de armazenamento:
          clear W; W=proj(X,X);        
          % Fase de Recordação;
          clear xout; clear it;
          [xout,it]=mad(W,xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(X'*xout)/n)<1;
             pme_personnaz(xi)=pme_personnaz(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_personnaz(xi)=it_personnaz(xi)+it;
          
          %
          % Memória Associativa de Kanter-Sompolinsky;
          %
          
          % Fase de armazenamento:
          clear W; W=proj0(X);        
          % Fase de Recordação;
          clear xout; clear it;
          [xout,it]=mad(W,xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(X'*xout)/n)<1;
             pme_kanter(xi)=pme_kanter(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_kanter(xi)=it_kanter(xi)+it;
          
          %
          % Memória Associativa com Capacidade Exponencial;
          %
          
          % Fase de Recordação;
          clear xout; clear it;
          [xout,it]=ecam(X,xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(X'*xout)/n)<1;
             pme_ecam(xi)=pme_ecam(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_ecam(xi)=it_ecam(xi)+it;
          
          %
          % Memórias Associativas Morfológicas;
          %
          Xb=(X+1)/2;
          xinb=(xin+1)/2;
          
          %
          % Memória Auto-associativa Morfológica Wxx;
          %
         
          if op_morf==1
             Xb(:,1)=ones(n,1);
             X(:,1)=ones(n,1);
          end

          % Fase de armazenamento:
          clear W; W=boxmin(Xb,-Xb');        
          % Fase de Recordação;
          clear xout;           
          xout=boxmax(W,xinb);
          % Transformando a saída em padrões bipolares;
          xout=2*xout-1;
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(X'*xout)/n)<1;
             pme_Wxx(xi)=pme_Wxx(xi)+1;
          end
          
          %
          % Memória Associativa Morfológica de Duas Camadas;
          %
         
          if op_morf==1
             Xb(:,1)=zeros(n,1);
             X(:,1)=(-1)*ones(n,1);
          end
         
          % Fase de Armazenamento;
          clear Z; Z=eye(vetk(xi));
          clear Wzy; clear Mxxz;
      	 Wzy=boxmin(Xb,-Z');
      	 Mxxz=boxmin(boxmax(Z,-Xb'),boxmax(Xb,-Xb'));
          % Fase de Recordação;
          clear xout;           
          xout=mam2c(Wzy,Mxxz,xinb);
          % Transformando a saída em padrões bipolares;
          xout=2*xout-1;
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(X'*xout)/n)<1;
             pme_mam2c1(xi)=pme_mam2c1(xi)+1;
          end
          
       end
       
       if caso==2
          %
          % Caso Heteroassociativo;
          %
          % Gerando a matriz contendo as recordações fundametais;
      	 Y=sign(2*rand(m,vetk(xi))-1);
          
          %
          % Memória Associativa Bidirecional;
          %
          
          % Fase de armazenamento:
          clear W; W=corr(X,Y);        
          % Fase de Recordação;
          clear yout; clear xout, clear it;
          [yout,xout,it]=madb(W,W',xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(Y'*yout)/m)<1;
             pme_bam(xi)=pme_bam(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_bam(xi)=it_bam(xi)+it;
          
          %
          % Memória Associativa Bidirecional Assimétrica;
          %
          
          % Fase de armazenamento:
          clear W1; W1=proj(X,Y);
          clear W2; W2=proj(Y,X);
          % Fase de Recordação;
          clear yout; clear xout, clear it;
          [yout,xout,it]=madb(W1,W2,xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(Y'*yout)/m)<1;
             pme_abam(xi)=pme_abam(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_abam(xi)=it_abam(xi)+it;
          
          %
          % Memória Associativa Bidirecional com Capacidade Exponencial;
          %
          
          % Fase de Recordação;
          clear yout; clear xout; clear it;
          [yout, xout, it]=becam(X,Y,xin);
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(Y'*yout)/m)<1;
             pme_becam(xi)=pme_becam(xi)+1;
          end
          % contando o número de iterações realizadas;
          it_becam(xi)=it_becam(xi)+it;
          
          %
          % Memórias Associativas Morfológicas;
          %
          Xb=(X+1)/2;
          Yb=(Y+1)/2;
          xinb=(xin+1)/2;
          
          %
          % Memória Auto-associativa Morfológica Wxx;
          %
         
          if op_morf==1
             Xb(:,1)=ones(n,1);
          end

          % Fase de armazenamento:
          clear W; W=boxmin(Yb,-Xb');        
          % Fase de Recordação;
          clear yout;           
          yout=boxmax(W,xinb);
          % Transformando a saída em padrões bipolares;
          yout=2*yout-1;
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(Y'*yout)/m)<1;
             pme_Wxy(xi)=pme_Wxy(xi)+1;
          end
          
          %
          % Memória Associativa Morfológica de Duas Camadas;
          %
         
          if op_morf==1
             Xb(:,1)=zeros(n,1);
          end
         
          % Fase de Armazenamento;
          clear Z; Z=eye(vetk(xi));
          clear Wzy; clear Mxxz;
      	 Wzy=boxmin(Yb,-Z');
      	 Mxxz=boxmin(boxmax(Z,-Xb'),boxmax(Xb,-Xb'));
          % Fase de Recordação;
          clear yout;           
          yout=mam2c(Wzy,Mxxz,xinb);
          % Transformando a saída em padrões bipolares;
          yout=2*yout-1;
          % Verificar se o padrão recordado não pertence 
          %    ao conjunto das memórias fundamentais;
          if (max(Y'*yout)/m)<1;
             pme_mam2c2(xi)=pme_mam2c2(xi)+1;
          end
       end
    end
    disp(sprintf('Faltam %d simulações. O tempo estimado para completar a execução é %d min.',simulacoes-s,ceil((simulacoes-s)*toc/60)));
end

if caso==1
   pme_hopfield=pme_hopfield/simulacoes;
   pme_personnaz=pme_personnaz/simulacoes;
   pme_kanter=pme_kanter/simulacoes;
   pme_ecam=pme_ecam/simulacoes;
   pme_Wxx=pme_Wxx/simulacoes;
   pme_mam2c1=pme_mam2c1/simulacoes;
   
   figure(1);
   clf;
   plot(vetk,pme_hopfield,vetk,pme_personnaz,vetk,pme_kanter,vetk,pme_ecam,vetk,pme_Wxx,vetk,pme_mam2c1);
   legend('MA Hopfield','MA Personnaz','MA Kanter-Somp.','ECAM','MAM Wxx','MAM 2 Camadas');
   xlabel('Número de Memórias Fundamentais Armazenadas','FontSize',12);
   ylabel('Probabilidade de Memória Espúria','FontSize',12);
   
   it_hopfield=it_hopfield/simulacoes;
   it_personnaz=it_personnaz/simulacoes;
   it_kanter=it_kanter/simulacoes;
   it_ecam=it_ecam/simulacoes;
   
   figure(2);
   clf;
   plot(vetk,it_hopfield,vetk,it_personnaz,vetk,it_kanter,vetk,it_ecam);
   legend('MA Hopfield','MA Personnaz','MA Kanter-Somp.','ECAM');
   xlabel('Número de Memórias Fundamentais Armazenadas','FontSize',12);
   ylabel('Número de Iterações','FontSize',12);
   
   if salvar==1
      save pme_auto pme_hopfield pme_personnaz pme_kanter pme_ecam pme_Wxx pme_mam2c1 vetk dim simulacoes;
      save it_auto it_hopfield it_personnaz it_kanter it_ecam vetk dim simulacoes;
      disp('Confira os resultados nos arquivos pme_auto.mat e it_auto.mat')
   end   
end

if caso==2
   pme_bam=pme_bam/simulacoes;
   pme_abam=pme_abam/simulacoes;
   pme_becam=pme_becam/simulacoes;
   pme_Wxy=pme_Wxy/simulacoes;
   pme_mam2c2=pme_mam2c2/simulacoes;
   
   figure(1);
   clf;
   plot(vetk,pme_bam,vetk,pme_abam,vetk,pme_becam,vetk,pme_Wxy,vetk,pme_mam2c2);
   legend('BAM','ABAM','BECAM','MAM Wxy','MAM 2 Camadas');
   xlabel('Número de Memórias Fundamentais Armazenadas','FontSize',12);
   ylabel('Probabilidade de Memória Espúria','FontSize',12);
   
   it_bam=it_bam/simulacoes;
   it_abam=it_abam/simulacoes;
   it_becam=it_becam/simulacoes;
   
   figure(2);
   clf;
   plot(vetk,it_bam,vetk,it_abam,vetk,it_becam);
   legend('BAM','ABAM','BECAM');
   xlabel('Número de Memórias Fundamentais Armazenadas','FontSize',12);
   ylabel('Número de Iterações','FontSize',12);
   
   if salvar==1
      save pme_heterp pme_bam pme_abam pme_becam pme_Wxy pme_mam2c2 vetk dim simulacoes;
      save it_hetero it_bam it_abam it_becam vetk dim simulacoes;
      disp('Confira os resultados nos arquivos pme_hetero.mat e it_hetero.mat')
   end   
end