:- lib(ordsets).	
          % list_to_ord_set/2, ord_add_element/3, ord_memberchk/2.

:- lib( kv_to_ord_k_v/3 ).

% [1-[],2-[1],3-[2,5],4-[],5-[4],6-[4],7-[3],8-[3,6]]

% Collapse == true ->  edges that appear in both direction will 1 link
%
band_bn( Bn, Collapse, [Pless,NoPorC,Cless] ) :-
	sieve_parentless( Bn, SivPless, WithParents ),
     ( Collapse == true -> 
	     clear_bidirectional( WithParents, NoBiWPar )
          ;
	     WithParents = NoBiWPar
     ),
	list_to_ord_set( SivPless, OrdSivPless ),
	kv_to_ord_k_v( WithParents, OrdCh, OrdPa ),
	induce_parentless( OrdPa, OrdCh, OrdSivPless, Pless, Induced ), 
	add_induced_parentless( Induced, Bn, CompBn ),
	sieve_childless( NoBiWPar, CompBn, Cless, NoPorC ).

add_induced_parentless( [], Bn, Bn ).
add_induced_parentless( [H|T], Bn, CompBn ) :-
	add_induced_parentless( T, [H-[]|Bn], CompBn ).

% this is meant to cope with essential graphs.
% use it as a trap to illegal bns otherwise.
clear_bidirectional( [], [] ).
clear_bidirectional( [Node-Parents|T], [Node-DblParents|R] ) :-
	clear_parents_from_remaining( Parents, Node, T, DblParents, Cleared ),
	clear_bidirectional( Cleared, R ).

clear_parents_from_remaining( [], _, Clear, [], Clear ).
clear_parents_from_remaining( [H|T], Node, Pairs, [DblH|DblT], Clear ) :-
	( reverse_edge_exists_in( Pairs, H, Node, NxPairs ) ->
		DblH = dbl(H)
		; 
		DblH = H, NxPairs = Pairs
	),
	clear_parents_from_remaining( T, Node, NxPairs, DblT, Clear ).

reverse_edge_exists_in( Pairs, H, Node, NxPairs ) :-
	select( H-HParents, Pairs, RemPairs ),
	select( Node, HParents, RedParents ),
	ord_add_element( RemPairs, H-RedParents, NxPairs ).

sieve_parentless( [], [], [] ).
sieve_parentless( [H|T], Pless, WithParents ) :-
	( H = Node-[] -> 
		Pless = [Node|Tpl],
		WithParents = Twp
		;
		Pless = Tpl,
		WithParents = [H|Twp]
	),
	sieve_parentless( T, Tpl, Twp ).

induce_parentless( [], _OrdCh, Pless, Pless, [] ).
induce_parentless( [H|T], OrdCh, AccPless, Pless, Ind ) :-
	% should change this to ord_memberchk/2 if SICStus supports this.
	( ord_memberchk(H,OrdCh) ->
		NextPless = AccPless, Ind = TInd
		;
		ord_add_element( AccPless, H, NextPless ),
		Ind = [H|TInd]
	),
	induce_parentless( T, OrdCh, NextPless, Pless, TInd ).

sieve_childless( [], _Bn, [], [] ).
sieve_childless( [Node-Parents|T], Bn, WPorC, Cless ) :-
	( childless(Bn,Node) -> 
		WPorC = [Node-Parents|Tporc],
		Cless = Tcl
		;
		WPorC = Tporc,
		Cless = [Node-Parents|Tcl]
	),
	sieve_childless( T, Bn, Tporc, Tcl ).

childless( [], _B ).
childless( [_A-Parents|T], B ) :-
	\+ ord_memberchk( B, Parents ), 
	childless( T, B ).
