function [dout,alg] =  training(a0,d)
  
  if a0.algorithm.verbosity>0
    disp(['training ' get_name(a0) '.... '])
  end


  nr_of_samples=length(d.X(:,1));
  dim_of_samples=length(d.X(1,:));
  
  
  V=get_x(d);  
  
  alg=a0;  
  dout=data([],d.X);
  
  
  r=nr_of_samples;

  if(isempty(a0.N))
      a0.N=dim_of_samples;
  end

  foundmodels=[];

  for seeking_model=1:a0.nrofrestarts
    foundmodels=[foundmodels;alg];

   W1=rand(nr_of_samples,a0.N);
   H1=rand(a0.N,dim_of_samples);

   W2=[];
   H2=[];
  
  error_old=inf; 
  
  difference=inf;
  
  error_difference=inf;
  
  iteration=0;
  error=inf;

  Derror_diff=1e-2;
  
  while error>eps && iteration < a0.maxIteration && error_difference>Derror_diff
      iteration=iteration+1;
      fprintf('%d  %f %f\n',[iteration ,error_difference , error])
%   optimize W
actual=W1*H1;


%--------------------------- Theorem 1  -------------------------------
% -------------------------------------------------------------------------
% 
%       implementation of PAPER : Algorithms for non negative Matrix factorization      
%      
%     numW=V*H1';
%     denumW=W1*H1*H1';
%     numH=W1'*V;     
%     denumH=W1'*W1*H1';

%     for i=1: nr_of_samples
%         for j=1: nr_of_samples
%          H2(i,j)=  H1(i,j)* numH(i,j)/denumH(i,j);
%          W2(i,j)=  W1(i,j)* numW(i,j)/denumW(i,j);

%      end
%     end
%     did not work ? who hte hell knows why...
% -------------------------------------------------------------------------




%for i=1: nr_of_samples
%    for a=1: a0.N
%        s=0;
%        for  k=1:dim_of_samples
%            s=s+((V(i,k)/(1e-12+actual(i,k))).*H1(a,k));
%        end      
            
%        W2(i,a)= W1(i,a)* s / (sum(W1(:,a))+1e-3) ;       
%    end
%end


%optimize H
%for a=1: nr_of_samples
%    for k=1: a0.N
%        s=0;
%        for  i=1:dim_of_samples
%            s=s+ W2(i,a)* V(i,k+)/(1e-12+actual(i,k));
%        end
            
%        H2(a,k)= H1(a,k)*s;        
%    end
%end


%--------------------------- Theorem 2  -------------------------------

%optimizing H
    for  a=1:a0.N
        for  mu=1:dim_of_samples

            s=0;
            d=0;
            
            for i=1:nr_of_samples
                if actual(i,mu) > 1e-3
                  s=s+W1(i,a)*V(i,mu)/actual(i,mu);    
              end
            end
            
            d=sum(W1(:,a));
            
            H2(a,mu)=H1(a,mu)*s/d;
        end    
    end

%optimizing  W  unclear if i should use new or new H
    for  i=1:nr_of_samples
        for  a=1:a0.N

            s=0;
            d=0;

            for mu=1:dim_of_samples
                if actual(i,mu) > 1e-3
                  s=s+H2(a,mu)*V(i,mu)/actual(i,mu);    
              end
            end
           
            d=sum(H2(a,:));
            
            W2(i,a)= W1(i,a)*s/d;

        end
    end
    
 

%       implementation of Nature PAPER 

    


     W1=W2;
     H1=H2;
     
     difference1=0;
     
     est=W1*H1;
    for i=1: nr_of_samples
        for a=1: dim_of_samples
            difference1 = difference1 + (V(i,a)-est(i,a))^2;
        end
    end
  
    
  if( difference1<error)
      
      alg.W=W1;
      alg.H=H1;
      foundmodels(seeking_model)=alg;
      
      error_new=difference1;

      error_difference=abs(error_new-error_old);
      
      error_old=error_new;
      error=error_new;
      disp('.')
    else
        Derror_diff=Derror_diff*2;      
    end
  
  end
  
  
end


   mi=1;
   m=Inf;
    
   for k=1:a0.nrofrestarts
    difference=0;
    est=foundmodels(k).W*foundmodels(k).H;
    for i=1: nr_of_samples
        for a=1: dim_of_samples
            difference = difference + (V(i,a)-est(i,a))^2;
        end
    end
    if(difference<m)
        mi=k;
        m=difference;
    end

   end

   alg=foundmodels(mi);
   
   dout.X=alg.W*alg.H;
   
   display(['NMF Reconstruction Error: '  sprintf('%f',m)]);
   
   
  if ~a0.algorithm.do_not_evaluate_training_error
  
  else
      display('eval training error');
  end
  

