function  [cpdag] = dag_to_cpdag(dags)
% (also works with a cell array of dags, returning a cell array of cpdags)
% DAG_TO_CPDAG produce a N*N matrix which values respect :
%
% 	If the edge is compelled then 1 on the edge.
%	If the edge is reversible then 1 on the edge and 1 in the reverse edge.
%
% Make sure that the entry is a DAG.
%
% See D.M. Chickering: "Learning Equivalence Classes of Bayesian-Network Structures".
%
% 
% philippe.leray@insa-rouen.fr,  olivier.francois@insa-rouen.fr

if ~iscell(dags)
    dag=cell(1,1);
    dag{1}=dags;
else
    dag=dags;
end

for da=1:length(dag)
    cpdags{da} = abs(label_edges(dag{da}));
end

if ~iscell(dags)
    cpdag=cpdags{1};
else
    cpdag=cpdags;
end

%%==============================================================================

function [label] = label_edges(dag)
% LABEL-EDGES produce a N*N matrix which values are
% 	+1 if the edge is compelled or
%	-1 if the edge is reversible.
% Make sure that the entry is a DAG.
%
% olivier.francois@insa-rouen.fr

N=length(dag);
[order xedge yedge] = order_edges(dag);
label = 2*dag; % all edges as unknown

NbEdges = length(xedge) ;
%xedge=x, yedge=y, %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


for Edge=1:NbEdges,
    xlow=xedge(Edge);
    ylow=yedge(Edge);
    if label(xlow,ylow)==2
        fin = 0;

        wcompelled = find(label(:,xlow)~=2);

        parenty = find(label(:,ylow)~=0);
        sonsy = find(label(ylow,:)~=0);

        for w = wcompelled
            if ~ismember(w,parenty)
                label(xlow,ylow)=1; 
                label(ylow,xlow)=0; %

                label(parenty,ylow)=1; % label(ylow,parenty)=0; %
                label(ylow,sonsy)=1; % label(sonsy,ylow)=0; %
                fin = 1;
            elseif fin == 0
                label(w,ylow)=1;
                label(ylow,w)=0; %
            end
        end
        if fin == 0
            parentx = [xlow ; find(label(:,xlow)~=0)];
            if ~isempty(mysetdiff(parenty,parentx))
                label(xlow,ylow)=1; %
                label(ylow,xlow)=0; %

                label(find(label(:,ylow)==2),ylow)=1;
                label(ylow,find(label(ylow,:)==2))=1; %
            else	
                label(xlow,ylow)=1;
                label(ylow,xlow)=0; %

                label(find(label(:,ylow)==2),ylow)=-1;
                label(ylow,find(label(ylow,:)==2))=-1; %
            end
        end
    end
end

%%%========================================================================================
function [order, x, y] = order_edges(dag)
% ORDER_EDGES produce a total (natural) ordering over the edges in a DAG.
% Make sure that the entry is a DAG.
%
% philippe.leray@insa-rouen.fr, olivier.francois@insa-rouen.fr
%
% 2 mai 2003

if acyclic(dag)==0
    error('Requires an acyclic graph');
end

N=length(dag);
order = zeros(N,N);

node_order = topological_sort(dag);
[tmp oo] = sort(node_order);

dag2=dag(node_order,node_order);
[x y]=find(flipud(dag2)==1);
nb_edges=length(x);

if nb_edges~=0
  order(sub2ind([N N],N+1-x,y))=1:nb_edges ;
end

order=order(oo,oo);
x=node_order(N+1-x);
y=node_order(y);

