function [Wopt, newrindice]=ReorderingResignning(Wb,Wo,X,H,rindice,yy,op,dir)
%
% Wb: filter matrix before optimization.
% Wo: filter matrix partially optimized.
% X : data matrix.
% indice: original indice. 
% rindice : remaining indice
% yy : yy-th optimization of a pair of hotizontal and vetical optimization.
% op: parameters

if(nargin~=8)
    narginerror;
end

if((strcmp(dir,'horizontal')~=1)&&(strcmp(dir,'vertical')~=1))
    error('Correctly specify the direction.'); 
end

% model 
model=op.f;

% Source matrix before optimization.
Sb=Wb*X;

% Source matrix partially optimized.
So=Wo*X;

% the number of indice.
Ni=length(rindice);

% the number of combination.
Nc=set_numberofcombinations(rindice,model);

% the number of components to be optimized.
N=set_numberofcomponents(yy,op,dir);

minval=zeros(N,Nc);
minindice=zeros(N,Nc);

% N=1, namely, when the component to be optimized is one.
if((strcmp(dir,'horizontal')==1)&&(op.xdim==op.ydim)&&(yy==op.ydim))
    if(N~=1)
        error('');
    end
    minval=optonecomponent(Sb,So,rindice,op,model,H,dir);
end

% N=1, namely, when the component to be optimized is one.
if((strcmp(dir,'vertical')==1)&&(yy==op.ydim-1))
    if(N~=1)
        error('');
    end
    minval=optonecomponent(Sb,So,rindice,op,model,H,dir);
end

% When N=1, we does not go in the below roop.
for ii=1:N-1    
    % adding some terms to evaluate already optimized components.
    minval(ii,:)=minval(ii,:)+add_terms(Sb,So,ii,yy,rindice,op,model,H,dir);
    
    % this table stores all of combinations of the adjacent component.
    table=zeros(Nc,Nc);
    
    for jj=1:Nc
        % find the indice of  already used indice to avoid overlapping selections of
        % indices.
        indiceofusedindice=[];
        if(ii~=1)
            indiceofusedindice=find_usedindice(minindice,ii,jj,model);           
        end
        
        if(sum(isinf(indiceofusedindice))==0) % no infinity elements.
            cjj=convertindex(jj,Ni);
            cS=Sb(rindice(cjj),:); if(Ni<jj); cS=-cS; end;
        
            adjS=make_adjacentS(Sb,jj,rindice,indiceofusedindice,model);
            cS=repmat(cS,[Nc,1]);

            table(jj,:)=compute_comb(cS,adjS,model);
        else
            % if infinity elements were found, insert inf. 
            table(jj,:)=inf;
        end
    end
    
    [minv,mini]=min(minval(ii,:)'*ones(1,Nc)+table);
    minval(ii+1,:)=minv;
    minindice(ii+1,:)=mini;

    % When minval = inf, the corresponding minindice is also inf.
    minindice(ii+1,minval(ii+1,:)==inf)=inf;
    
    % adding the last term.
    if(ii==N-1)
        minval(ii+1,:) = minval(ii+1,:)+...
            add_lastterm(Sb,So,yy,rindice,op,model,H,dir);
    end
end

[optind,optsign]=extract_optindicesign(minval,minindice,rindice,N);

[Wopt, newrindice]=make_optW_rindice(Wb,Wo,optsign,optind,rindice,yy,op,dir);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function sign=determiningsign(ind,Ni)

if(Ni<ind)
    sign=-1;
else
    sign=1;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function cind=convertindex(ind,Ni)

if(Ni<ind)
    cind=ind-Ni;
else
    cind=ind;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [optind,optsign]=extract_optindicesign(minval,minindice,rindice,N)

if(nargin~=4)
    narginerror();
end

Ni=length(rindice);

optind=zeros(N,1);
optsign=zeros(N,1);

for ii=N:-1:1
    if(ii==N)
        [~,optind(ii)]=min(minval(ii,:));        
    else
        tmpind=optind(ii+1);
        
        optind(ii)=minindice(ii+1,tmpind);
    end
    optsign(ii)=determiningsign(optind(ii),Ni);
end

optind(Ni<optind)=optind(Ni<optind)-Ni;
optind=rindice(optind);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [Wopt, newrindice]=make_optW_rindice(Wb,Wo,optsign,optind,rindice,yy,op,dir)

if(nargin~=8)
    narginerror();
end

stindex=set_startindex(yy,dir);

Wopt=Wo;

dim=size(Wb,2);

if(strcmp(dir,'horizontal')==1)
    tmpindex=stindex:op.xdim;
    Wopt((yy-1)*op.xdim+tmpindex,:)=(optsign*ones(1,dim)).*Wb(optind,:);
elseif(strcmp(dir,'vertical')==1)
    tmpindex=stindex:op.ydim;
    Wopt((tmpindex-1)*op.xdim+yy,:)=(optsign*ones(1,dim)).*Wb(optind,:);    
end

% Updating the remaining indice.
newrindice=abs(ismember(rindice,optind)-1).*rindice;
newrindice(newrindice==0)=[];