1:- module(crbd, []).    2
    3:- use_module(zdd('zdd-array')).    4:- use_module(zdd(zdd)).    5:- use_module(pac(op)).    6
    7		   13
   16
   23
   27
   32
   35
   36udg_path(End, PathSet):- get_key(coa, Coa),
   37	set_key(ends, End),
   38	udg_mate_prune(Coa, 1, PathSet).
   39
   40		   47
   54
   62
   71udg_path_count(Ends, Links, C):- udg_path_count(Ends, Links, C, _).
   73udg_path_count(Ends, Links, C, X):-
   74		prepare_udg(Ends, Links),
   75		!,
   76		get_key(coa, Coa),
   77		udg_mate_prune(Coa, 1, X),
   78		card(X, C).
   80udg_mate_prune(Ls, X, Y):-
   81	add_links(Ls, X, Y0),
   82	prune_final(Y0, Y).
   83
   93
   94rect_path_count(R, C):- R = rect(W, H),
   95	rect_path_count( p(0,0) - p(W,H), R, C, _).
   97rect_path_count(Ends, R, C, X):- rect_links(R, Links),
   98	udg_path_count(Ends, Links, C, X).
   99
  102rect_links(rect(W, H), Links):-
  103	findall( p(I,J) - p(K,L),
  104				 (	between(0, W, I),
  105					between(0, H, J),
  106					(  L = J, K is I + 1, K =< W
  107					;  K = I, L is J + 1, L =< H
  108					)
  109				 ),
  110				 Links).
  111
  112		  115
  119
  128
  137
  143
  144prepare_udg(ST, Links):-
  145	prepare_udg(Links),
  146	prepare_ends(ST, A-B),
  147	set_key(ends, A-B).
  149prepare_udg(Links):-
  150	prepare_udg(Links, Succs, D, Vec),
  151	length(D, N),
  152	completing_succs(Succs, Succs0, N),
  153	set_key(coa, Succs0),
  154	set_key(dom, D),
  155	set_key(frontier, Vec).
  157prepare_udg(Links, Succs, D, Vec):-
  158	intern_links(Links, Links0),
  159	normal_mate_list(Links0, Links1),
  160	sort(Links1, Links2),
  161	domain_of_links(Links2, D),
  162	rel_to_fun(Links2, Succs),
  163	Vec=..[#|D],
  164	setup_frontier(Links1, Vec).
  166prepare_ends(A-B, R):-!, R = A0-B0,
  167	memo(node_id(A)-I),
  168	memo(node_id(B)-J),
  169	(	nonvar(I), nonvar(J) -> sort([I, J], [A0, B0])
  170	;	format("No link at ~w or ~w\n", [A,B]),
  171		fail
  172	).
  173prepare_ends(E, _):-
  174	format("Unexpected form of end nodes ~w \n", [E]),
  175	fail.
  176
  179completing_succs(X, X, 0):-!.
  180completing_succs([I-A|Ls], [I-A|Ms], I):-!, J is I - 1,
  181	completing_succs(Ls, Ms, J).
  182completing_succs(Ls, [I-[]|Ms], I):- J is I - 1,
  183	completing_succs(Ls, Ms, J).
  184
  187normal_mate_list([], []).
  188normal_mate_list([P|R], [P0|R0]):- P = I-J,
  189	(	J @< I -> P0 = J - I
  190	;	P0 = P
  191	),
  192	normal_mate_list(R, R0).
  202rel_to_fun(L, R):- sort(L, L0), rel_to_fun(L0, [], R).
  204rel_to_fun([], X, X).
  205rel_to_fun([A-B|L], [A-U|V], R):-!,
  206	rel_to_fun(L, [A-[B|U]|V], R).
  207rel_to_fun([A-B|L], U, R):-!,
  208	rel_to_fun(L, [A-[B]|U], R).
  209
  211domain_of_links(X, Y):-
  212	findall(A , (	member(L, X),
  213					( L = (A - _)
  214					; L = (_ - A)
  215					)
  216				),
  217		   Y0),
  218   sort(Y0, Y).
  219
  221node_id(N, C, C0):- node_id(N, _, C, C0).
  222
  229
  230node_id(N, I, C, C0):- memo(node_id(N)-I),
  231	(	nonvar(I) -> C0 = C
  232	;	C0 is C+1,
  233		I = C0
  234	).
  235
  238intern_links(L, L0):- intern_links(L, L0, 0, _).
  240intern_links([], [], C, C).
  241intern_links([A-B|L], [I-J|M], C, D):-
  242	node_id(A, I, C, C0),
  243	node_id(B, J, C0, C1),
  244	intern_links(L, M, C1, D).
  245
  246		
  256on_frontier(I, J, F):- arg(I, F, K), J > K.
  263off_frontier(I, J, F):- arg(I, F, K), J =< K.
  264
  266setup_frontier([], _).
  267setup_frontier([I-J|L], F):-
  268	update_frontier(I, J, F),
  269	!,
  270	setup_frontier(L, F).
  271
  274update_frontier(I, J, V):-
  275	arg(J, V, A),
  276	(	I < A -> setarg(J, V, I)
  277	;	true
  278	).
  279
  280
  281		  284add_links([], X, X):-!.
  285add_links([A-Ns|Ls], X, Y):-!,
  286	cofact(X0, t(n(A,0,A), 0, X)),
  287	add_links(A, Ns, X0, X1),
  288	prune_by_frontier(A, X1, X2),
  289	add_links(Ls, X2, Y).
  291add_links(_, [], X, X):-!.
  292add_links(A, [B|Ns], X, Y):-
  293	add_link(A-B, X, X0),
  294	zdd_join(X, X0, X1),
  295	add_links(A, Ns, X1, Y).
  297add_link(_, X, 0):- X<2, !.
  298add_link(I-J, X, Y):-
  299	cofact(X, t(A, L, R)),
  300	add_link(I-J, L, L0),
  301	A = n(K,G,C),
  302	(	I @< K -> R0 = 0
  303	;	G = 2 -> R0  = 0
  304	;	K = I ->
  305		update_class_degree(J, C, R, R1),
  306		cleanup_dot_star(R1,  R2),
  307		G1 is G + 1,
  308		A1 = n(I, G1, C),
  309		zdd_insert(A1, R2, R0)
  310	;	add_link(I-J, R, R1),
  311		zdd_insert(A, R1, R0)
  312	),
  313	zdd_join(L0, R0, Y).
  315update_class_degree(_, _, X, 0):- X < 2, !.
  316update_class_degree(J, C, X, Y):- cofact(X, t(V, L, R)),
  317	update_class_degree(J, C, L, L0),
  318	V = n(K, G, C0),
  319	(	J = K ->
  320		(   G = 2 -> R0 = 0		  321		;	C = C0 -> R0 = 0	  322		;	G1 is G + 1,
  323			subst_class_id(C0, C, R, R1),    324			zdd_insert(n(K, G1, C), R1, R2),
  325			cofact(R0, t(*, change(C0, C), R2))
  326		)
  327	;	update_class_degree(J, C, R, R1),
  328		insert_through_dot(V, R1, R0)
  329	),
  330	cofact(Y, t((.), L0, R0)).
  332subst_class_id(_, _, X, X):-X<2,!.
  333subst_class_id(C, D, X, Y):- cofact(X, t(U,L,R)),
  334	subst_class_id(C, D, L, L0),
  335	subst_class_id(C, D, R, R0),
  336	U = n(I, G, C0),
  337	(   C = C0 -> C1 = D
  338	;   C1 = C0
  339	),
  340	cofact(Y, t(n(I, G, C1), L0, R0)).
  342cleanup_dot_star(X, X):- X<2, !.
  343cleanup_dot_star(X, Y):- cofact(X, U),
  344	cleanup_dot_star_case(U, Y).
  346cleanup_dot_star_case(t(., L, R), V):-!,
  347	cleanup_dot_star(R, R0),
  348	cleanup_dot_star(L, L0),
  349	zdd_join(L0, R0, V).
  350cleanup_dot_star_case(t(*, _, R), R):-!.
  351cleanup_dot_star_case(X, X).
  352
  354insert_through_dot(_, X, 0):- X<2, !.
  355insert_through_dot(A, X, Y):- cofact(X, T),
  356	T = t(U, L, R),
  357	(	U = (.) ->
  358		insert_through_dot(A, L, L0),
  359		insert_through_dot(A, R, R0),
  360		cofact(Y, t(U, L0, R0))
  361	;	U = (*) ->
  362		insert_aside_star(A, T, Y)
  363	).
  365insert_aside_star(n(I, Deg, C), T,  Y):-
  366	T = t(*, change(C0, C1), R),
  367	( C = C0 -> N = n(I, Deg, C1)
  368	; N = n(I, Deg, C)
  369	),
  370	zdd_insert(N, R, R0),
  371	cofact(Y, t(*, change(C0, C1), R0)).
  372
  373		  376
  377prune_by_frontier(I, X, Y):-
  378	get_key(frontier, V),
  379	get_key(ends, M),
  380	prune_by_frontier(X, Y, I, M, V).
  387prune_by_frontier(X, X, _, _, _):- X<2, !.
  388prune_by_frontier(X, Y, I, M, V):- cofact(X, t(A, L, R)),
  389	classify_triple(A, I, M, V, C),
  390	prune_by_frontier(L, L0, I, M, V),
  391	(	C = keep ->
  392		prune_by_frontier(R, R1, I, M, V),
  393		zdd_insert(A, R1, R0)
  394	;	R0 = 0
  395	),
  396	zdd_join(L0, R0, Y).
  397
  398
  400on_pair(J, J-_).
  401on_pair(J, _-J).
  402
  404classify_triple(n(J, Deg, _), I, Pair, V, C):-!,
  405	(	on_frontier(J, I, V) -> C = keep
  406	;	(	on_pair(J, Pair) ->
  407			(	Deg = 1 -> C = keep
  408			;	C = 0
  409			)
  410		;	(	Deg = 1 -> C = 0
  411			;	C = keep
  412			)
  413		)
  414	).
  416prune_final(X, Y):-
  417	get_key(ends, Pair),
  418	prune_final(Pair, X, Y).
  419
  421prune_final(_, X, X):- X<2, !.
  422prune_final(Pair, X, Y):- cofact(X, t(A, L, R)),
  423	prune_final(Pair, L, L0),
  424	A = n(_, _, C),
  425	prune_final(C, Pair, R, R1),
  426	zdd_insert(A, R1, R0),
  427	zdd_join(L0, R0, Y).
  429prune_final(_, _, X, X):- X<2, !.
  430prune_final(C0, Pair, X, Y):- cofact(X, t(A, L, R)),
  431	prune_final(C0, Pair, L, L0),
  432	A = n(J, Deg, C),
  433	( 	on_pair(J, Pair) ->
  434		(	Deg = 1 -> prune_final(C0, Pair, R, R0)
  435		;   R0  = 0
  436		)
  437	;	(	Deg = 1 -> R0 = 0
  438		;	Deg = 2 ->
  439			(	C0 = C ->
  440				prune_final(C, Pair, R, R1),
  441				zdd_insert(A, R1, R0)
  442			;	R0 = 0
  443			)
  444		;	prune_final(C0, Pair, R, R1),
  445			zdd_insert(A, R1, R0)
  446		)
  447	),
  448	zdd_join(L0, R0, Y)