function [PDAGs, nodes] = mk_nbrs_of_pdag_add(cpdag,engine)
% MK_NBRS_OF_PDAG_ADD Make the superior inclusion boundary of CPDAG.
% [PDAGs, nodes] = mk_nbrs_of_pdag_add(CPDAG)
%
% PDAGs{i} is the i'th neighbor of CPDAG0 generated by INSERT(X,Y,T)  with
% nodes{i,1:2}=[X Y]
% nodes{i,3}=T
%
% See D.M. Chickering 2002 : "Optimal Structure Identification with Greedy Search".
%
% philippe.leray@univ-nantes.fr, francois.olivier.c.h@gmail.com
% 24 july 2003


compteur=0 ;
N=length(cpdag);
G=pdag_to_dag(cpdag);
if nargin==1,
 bnet_tmp=mk_bnet(pdag_to_dag(cpdag),2*ones(N,1));
 bnet_tmp=mk_bnet(G,2*ones(N,1));
 engine_tmp=struct(jtree_inf_engine(bnet_tmp));
 clear bnet_tmp
else
 engine_tmp=struct(engine);
end
cliques=engine_tmp.cliques;
nbcliques=length(cliques);
clear engine_tmp;

% find in the PDAG all the X Y not connected
[LX LY]=find((cpdag|cpdag')+eye(N)==0);
nlinks=length(LX); % here is a bug when nlinks is zeros, for i=1:nlinks fail 31-37 added by hanbin
if nlinks==0
   [i,j]=find(cpdag);k=unidrnd(size(i,1),1);
   cpdag(i(k),j(k))=0;
   [LX LY]=find((cpdag|cpdag')+eye(N)==0);
    nlinks=length(LX);
end

for i=1:nlinks
    X=LX(i);
    Y=LY(i);
    % Neighbors of Y
    NY = myintersect(find(cpdag(:,Y)), find(cpdag(Y,:)));
    % Adjacents of X
    AX =  myunion(find(cpdag(:,X)), find(cpdag(X,:)));
    % Neighbors of Y adjacent to X
    NAYX = myintersect(NY,AX);
    % Neighbors of Y NOT adjacent to X
    NNAYX = mysetdiff(NY, NAYX);

    % this function recursively "walks" (dfs) in the graph representation of NNA powerset
    liste=NNAYX;
    if ~isempty(liste)
        premier=liste(1);
        dernier=liste(end);
    end;

    current_set=[];
    fini=0;
    evite2 = 0 ;

    while ~fini
        isclique=0;
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Test 1
        % is [NAYX current_set] a clique ?
        if isempty(current_set)
            NAYXT=NAYX;
        elseif isempty(NAYX)
            NAYXT=current_set;
        else
            NAYXT = union(NAYX,current_set);
        end
        % if isempty(NAYXT),isclique=1;end

        isclique = isempty(NAYXT) | ismemberclique(NAYXT,cliques) ;
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End Test 1

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Test 2
        % is there exist a partially directed path Y...X in PDAG \ NAYXT ?
        if isclique  
            if evite2
                test2=1 ;
            else
                %%%% calcul test 2
                L2 = setdiff(1:N,NAYXT);
                test2=~partialconnected(cpdag(L2,L2),find(L2==Y),find(L2==X));

            end
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End Test 2

            if test2
                evitet2=1;

                % avoid testing INSERT(X,Y,[]) and INSERT(Y,X,[]) if pa(Y)=pa(X)
                test0=1 ;
                if (X>Y)
                    if length(current_set)==0
                        PaX=setdiff(find(cpdag(X,:)),find(cpdag(:,X)));
                        PaY=setdiff(find(cpdag(Y,:)),find(cpdag(:,Y)));
                        test0=(length(setdiff(PaX,PaY))~=0);
                    end
                end
                if test0
                    %fprintf(' INSERT(%d,%d,',X,Y); fprintf('%d',current_set);
                    %fprintf(')\n');
                    compteur=compteur+1;
                    nodes{compteur,1}=X;
                    nodes{compteur,2}=Y;
                    nodes{compteur,3}=current_set;
                    ptmp=cpdag;
                    ptmp(X,Y)=1;
                    ptmp(current_set,Y)=1;
                    ptmp(Y,current_set)=0;
                    PDAGs{compteur}=ptmp;
                end
            end
        end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Next Set to test ...
        % what is the net set in the powerset ?
        if length(liste)==0
            fini=1 ; next_set=[];
        elseif length(current_set)==0
            next_set=[premier];     % first node after the root []
        else
            actuel=current_set(end);
            if actuel==dernier 
                if length(current_set)==1
                    fini=1;            % no more node ...
                else
                    ancien=current_set(end-1);  % new "branch"
                    next_set=[current_set(1:end-2) liste(find(liste==ancien)+1)];
                end
            else                            % new node in the "branch"
                if ~isclique
                    if length(current_set)==1
                        fini=1;            % no more node ...
                    else
                        ancien=current_set(end-1);  % new "branch"
                        next_set=[current_set(1:end-2) liste(find(liste==ancien)+1)];
                        evite2=0;
                    end
                else
                    next_set=[current_set liste(find(liste==actuel)+1)];
                end
            end
        end
        current_set=next_set;
    end
end


%%%%%%%%%
function resu = ismemberclique(v,cliques)
finiclique = 0 ; resu=0 ; 
cl=1;  ncl=length(cliques) ;
while (~finiclique) & (cl<=ncl);
    if ismember(v,cliques{cl})
        resu=1;
        finiclique=1 ;
    end
    cl=cl+1;
end

%%%%%%%%%
function resu = partialconnected(G,Y,X)
tmp=expm(G);
resu = (tmp(Y,X)~=0);
