1:- module(coalgebra, [show_am/1, regex_to_pdf/2, regex_to_pdf/3,
    2		      gv/1]).
?- gv(a). ?- gv("ab").
    7% ?- show_am(a+b).
    8% ?- show_am("([a-d])*[b-e]").
    9% ?- show_am("c|a|b|c").
   10% ?- show_am("cabc").
   11% ?- show_am("(ca)|(bc)").
   12% ?- show_am("(ca)+(bc)").
   13% ?- time(show_am("^(.*)/([^/]*)")).
   14
   15% ?- time(show_am("^(.*)/([^/]*)$")).
   16
   17
   18:- use_module(library(lists)).   19:- use_module(pac(basic)).   20:- use_module(pac('expand-pac')).   21:- use_module(pac('expand-word')).   22:- use_module(util(misc)).   23:- use_module(util(math)).   24:- use_module(util('emacs-handler')).   25:- use_module(util(meta2)).   26:- use_module(util(file)).   27:- use_module(util(obj)).   28:- use_module(util(web)).   29
   30term_expansion --> pac:expand_pac.
   31:- use_module(pac(op)).   32
   33% :- set_prolog_flag(unknown, fail).
   34% :- expand_file_name('~', X), log(X). % empty string.
   35:-op(750, yfx, &).   36
   37signature([(^)/2,(+)/2,(\)/2,(&)/2,(#)/2,(-)/1,(*)/1,reverse/1]).
   38
   39%  'coa' stands for coalgebra; 'sts', state transition system;
   40%  am, automaton;  dfam, deterministic finite automaton
   41% ?- trace, coalgebra:compose_am((a+b)^(c+d), X).
   42
   43% ?- qcompile(util(coalgebra)).
   44% ?- module(coalgebra).
   45% ?- am(a, X).
   46% ?- am(a+b, X).
   47% ?- am(a^b, X).
   48% ?- compose_am(*(a), X).
   49
   50compose_am(E, C):- symbols(E, S),
   51	preprocess_complement(S, E, E0),
   52	am(E0, C0),
   53	remove_dead_states(C0, C).
   54
   55dfam --> call, det_am, minimum_am, refresh_am.
   56
   57% ?- listing(am).
   58
   59am(empty,A1):-!,ampty_am(A1) .
   60am(epsilon,A1):-!,epsilon_am(A1) .
   61am(A+B,A1):-!,(am(A,A2),am(B,A3)),dfam(disj_am(A2,A3),A1) .
   62am(A&B,A1):-!,(am(A,A2),am(B,A3)),dfam(conj_am(A2,A3),A1) .
   63am(A^B,A1):-!,(am(A,A2),am(B,A3)),dfam(concat_am(A2,A3),A1) .
   64am(*A,A1):-!,am(A,A2),dfam(star_am(A2),A1) .
   65am((A\B),A1):-!,(am(A,A2),am(B,A3)),dfam(subtr_am(A2,A3),A1) .
   66am(#(A,B),A1):-!,(am(A,A2),am(B,A3)),dfam(xor_am(A2,A3),A1) .
   67am(reverse(A),A1):-!,am(A,A2),dfam(reverse_am(A2),A1) .
   68am(X,am([(1,[(X,[2])]),(2,[])],1,[2])):-! .
Kleene closure and set difference
   74empty_am(am([ (1,[])],1, [])).
   75
   76epsilon_am(am([ (1,[])],1, [1])).
   77
   78conj_am(X, Y, Z):- prod_am(conj, X, Y, Z).
   79
   80disj_am(X, Y, Z):- prod_am(disj, X, Y, Z).
   81
   82concat_am(am(C0,I0,F0), Am1, Am):-
   83	length(C0, L),
   84	L1 is L+1,
   85	refresh_am(Am1, am(C1, I1, F1), L1, _),
   86	product(F0, [I1], E),
   87	append(C0, C1, H),
   88	join_am(E, am(H,I0,F1), Am).
   89
   90star_am(am(C,I,F), Am):-
   91	product(F, [I], E),
   92	join_am(E, am(C,I,[I|F]), Am).
   93
   94subtr_am(X, Y, Z):- prod_am(subtr, X, Y, Z).
   95
   96xor_am(X, Y, Z):- prod_am(xor, X, Y, Z).
   97
   98reverse_am(Am0, Am) :-
   99	am_sts(Am0, sts(S0, I, F)),
  100	maplist(reverse_triple, S0, S),
  101	sts_coa(S, C),
  102	length(C, L), N is L+1,
  103	product([N], F, E),
  104	join_am(E, am([(N, [])|C], N, [I]), Am).
  105
  106join_am(R, am(C0, I0, F0), am(C1, I0, F1)):- join_link(R, C0, C1),
  107	foldl(propagate_final_state, R, F0, F1).
  108
  109%
  110prod_am(FinalPred, am(C0, I0, F0), am(C1, I1, F1), am(C, I, F)):-
  111	coalgebra([(I0, I1)], product_coa(p(C0, C1)), C2),
  112	refresh_coa(C2, C, 1, Assoc),
  113	assoc(Assoc, (I0, I1), I),
  114	maplist(fst, C2, S),
  115	call(FinalPred, S, F0, F1, F2),
  116	maplist(assoc(Assoc), F2, F).
  117
  118conj(S, F0, F1, F):- collect(conj(F0, F1), S, F).
  119
  120conj(F0, F1, (X, Y)):- memberchk(X, F0), memberchk(Y, F1).
  121
  122disj(S, F0, F1, F):- collect(disj(F0, F1), S, F).
  123
  124disj(F0, F1, (X, Y)):- (memberchk(X, F0);  memberchk(Y, F1)), !.
  125
  126subtr(S, F0, F1, F):- collect(subtr(F0, F1), S, F).
  127
  128subtr(F0, F1, (X, Y)):- (memberchk(X, F0),  \+ memberchk(Y, F1)), !.
  129
  130xor(S, F0, F1, F):- collect(xor(F0, F1), S, F).
  131
  132xor(F0, F1, (X, Y)):-
  133	(  memberchk(X, F0),  \+ memberchk(Y, F1)
  134	;  \+ memberchk(X, F0),  memberchk(Y, F1)
  135	),
  136	!.
  137
  138product_coa(X, Y, Z, U):-product_coa(X, Y, Z),
  139	union_image(Z, U).
  140
  141product_coa(_, (0, 0), []):-!.
  142product_coa(p(_, C1), (0, X1), Y):- !, memberchk((X1, Y1), C1),
  143	maplist(pairing_fst(0), Y1, Y).
  144product_coa(p(C0, _), (X0, 0), Y):- !, memberchk((X0, Y0), C0),
  145	maplist(pairing_snd(0), Y0, Y).
  146product_coa(p(C0, C1), _, []):- (C0 = []; C1=[]), !.
  147product_coa(p(C0, C1), (X0, X1), Y):-
  148	memberchk((X0, Y0), C0),
  149	memberchk((X1, Y1), C1),
  150	product_coa0(Y0, Y1, Y).
  151
  152product_coa0([], R1, R):-!, maplist(pairing_fst(0), R1, R).
  153product_coa0(R0, [], R):-!, maplist(pairing_snd(0), R0, R).
  154product_coa0([(X,[Y0])|R0], [(X,[Y1])|R1], [(X, [(Y0, Y1)])|R]):-!,
  155	product_coa0(R0, R1, R).
  156product_coa0([(X0,[Y0])|R0], [(X1,[Y1])|R1], [(X0, [(Y0, 0)])|R]):-
  157	X0 @< X1, !, product_coa0(R0, [(X1,[Y1])|R1], R).
  158product_coa0([(X0,[Y0])|R0], [(X1,[Y1])|R1], [(X1, [(0, Y1)])|R]):-
  159	product_coa0([(X0,[Y0])|R0], R1, R).
  162det_am(am(C, I, F), Am):-
  163	pow_coa(I, C, D0),
  164	maplist(fst, D0, S0),
  165        collect(meet(F), S0, F0),
  166	refresh_dfam(am(D0, [I], F0), Am).
  167
  168%%% coalgebra/3 (generalized sub_coa, inspired by `F-coalgebra')
  169coalgebra(X, Y, Z) :- coalgebra(X, Y, [], Z0), sort(Z0, Z).
  170
  171coalgebra([], _, X, X).
  172coalgebra([N|Ns], Generator, Y, Z) :- call(Generator, N, U, Sucs), !,
  173	Y1 = [(N, U) | Y],
  174	new_nodes(Sucs, Y1, D1),
  175	union(D1, Ns, Ms),
  176	coalgebra(Ms, Generator, Y1, Z).
sub_coa(X, C, Z, U). X: subset of domain(C). C: coalgebra Z: restriction of U. U: the minimum subcoalgebra of C over X.

?- sub_coa([1], comma_set([(1,[(a,1),(b,1)]), (2,[(a, 1), (b,2)])]), [], X). X = [ (1, [ (a, 1), (b, 1)])] ?- sub_coa([[1]], pow_merge(eq_set([ 1 = [ (a,[2]), (b,[1,2]) ], 2 = [(a,[1]),(b,[1])]])), X). X = [ ([1, 2], [ (a, [1, 2]), (b, [1, 2])]), ([2], [ (a, [1]), (b, [1])]), ([1], [ (a, [2]), (b, [1, 2])])]

  190sub_coa(X, Y, Z) :- sub_coa(X, Y, [], Z0), sort(Z0, Z).
  191
  192sub_coa([], _, X, X).
  193sub_coa([N|Ns], Generator, Y, Z) :- call(Generator, N, U), !,
  194	Y1 = [(N, U) | Y],
  195	maplist(snd, U, D),
  196	new_nodes(D, Y1, D1),
  197	union(D1, Ns, Ms),
  198	sub_coa(Ms, Generator, Y1, Z).
  199
  200% ?- sts_coa(1, [(1,a,2), (1, b, 1), (2, a, 1)], P).
  201% ?- sts_coa(1, [(1,a,2), (1, b, 1), (1, b, 2), (2, a, 1)], P).
  202% P = [ ([1, 2], [ (a, [1, 2]), (b, [1, 2])]), ([2], [ (a, [1])]), ([1], [ (a, [2]), (b, [1, 2])])]
  203% ?- sts_coa([(1,a,2),(1, a, 1), (1, b, 1), (2, a, 1)], Ts), pow_coa(1, Ts, P).
  204% P = [ ([1], [ (a, [1, 2]), (b, [1])]), ([1, 2], [ (a, [1, 2]), (b, [1])])]
  205% ?- sts_coa([(1,a,2), (1, b, 1), (1, b, 2)], P).
  206% P = [ (1, [ (a, [2]), (b, [1, 2])]), (2, [])]
  207
  208sts_coa(S0, Ts, P) :- sts_coa(Ts, C),
  209	sub_coa([[S0]], pow_merge(comma_set(C)), P).
  210
  211sts_coa(Ts, C):- maplist(triple_pair, Ts, Ts0),
  212	foldl(extend_coa, Ts0, [], C0),
  213	range_of_triples(Ts, F),
  214	maplist(pair_with_empty, F, Ps),
  215	merge_coa(Ps, C0, C).
  216
  217% ?- sts_am(sts([(1, a, 1), (1, a, 2), (1, b, 2), (2, a, 3)], 1, [1]), D).
  218% D = coa([ (1, []), (2, [ (a, 1)]), (3, [ (a, 3), (b, 2)]), (4, [ (a, 3), (b, 2)]), (5, [ (a, 4), (b, 2)])], 5, [3, 4, 5])
  219
  220sts_am(sts(T, I, F), Am):- sts_coa(T, C), det_am(am(C, I, F), Am).
  224pow_coa(S0, Ts, P) :- coalgebra([[S0]], pow_image(comma_set(Ts)), P).
  225
  226pow_image(Gen, Xs, R, Ys):- maplist(Gen, Xs, R0),
  227	foldl(foldl(extend(contract_merge)), R0, [], R),
  228	maplist(snd, R, Ys).
  229
  230pow_merge(A, X, R):- maplist(A, X, R0),
  231	foldl(foldl(extend(contract_merge)), R0, [], R).
  232
  233new_nodes([], _, []).
  234new_nodes([N|Ns], L, Ms) :- member((N, _), L)
  235	->  new_nodes(Ns, L, Ms)
  236	;   Ms=[N|Ms0], new_nodes(Ns, L, Ms0).
  237
  238% ?- extend_coa((a, [(1,[2])]), [(a,[(2,[4])])], X).
  239% X = [ (a, [ (1, [2]), (2, [4])])]
  240
  241merge_coa(X, Y, Z):- foldl(extend_coa, X, Y, Z).
  242
  243extend_coa(X, Y, Z):- extend(merge_indexed_family_of_sets, X, Y, Z).
  244
  245% ?- merge_indexed_family_of_sets([(1,[2]), (2,[3])], [(2,[4])], X).
  246% X = [ (1, [2]), (2, [4, 3])]
  247
  248merge_indexed_family_of_sets(X, Y, Z):- foldl(extend(contract_merge),X, Y, Z).
  249
  250extend(F, (X, S0), [(X, S1)|R], [(X, S2)|R]):-!, call(F, S0, S1, S2).
  251extend(F, (X, S0), [(Y, S1)|R0], [(Y, S1)|R]):-  X@>Y, !,
  252	extend(F, (X, S0), R0, R).
  253extend(F, (X, S0), R, [(X, S)|R]):- call(F, S0, [], S).
  254
  255
  256% ?- coalgebra:contract_merge([1,3,6], [2, 5, 7], R).
  257%@ R = [1, 2, 3, 5, 6, 7].
  258
  259%  Remark.
  260% ?- union([1,3,6], [2, 5, 7], R).
  261%@ R = [1, 3, 6, 2, 5, 7].
  262% ?- union([1,3,6], [2, 3,  5, 7], R).
  263%@ R = [1, 6, 2, 3, 5, 7].
  264
  265contract_merge([], X, X):-!.
  266contract_merge(X, [], X):-!.
  267contract_merge([X|R], [X|S], [X|T]):- !, contract_merge(R, S, T).
  268contract_merge([X|R], [Y|S], [X|T]):- X@<Y, !, contract_merge(R, [Y|S], T).
  269contract_merge([X|R], [Y|S], [Y|T]):- contract_merge([X|R], S, T).
  270
  271
  272% ?- coalgebra:contract_insert(3, [2, 5, 7], R).
  273%@ R = [2, 3, 5, 7].
  274
  275contract_insert(X, [], [X]):-!.
  276contract_insert(X, [X|S], [X|S]):- !.
  277contract_insert(X, [Y|S], [X, Y|S]):- X@<Y, !.
  278contract_insert(X, [Y|S], [Y|R]):- contract_insert(X, S, R).
  279
  280
  281%%%%  refresh coalgebra by renaming states
  282refresh_dfam(A, B) :- refresh_dfam(A, B, 1,  _).
  283
  284refresh_dfam(am(A,I,F), am(B,J,G), N, A_list) :-
  285	make_assoc(A, N, A_list),
  286	maplist(refresh_state_dfam(A_list), A, B),
  287	maplist(assoc(A_list), [I|F], [J|G]).
  288
  289
  290refresh_state_dfam(A, (X, S), (Y, T)):- assoc(A, X, Y),
  291	maplist(refresh_right_dfam(A), S, T).
  292
  293refresh_right_dfam(Assoc, (A, S), (A, [S1])) :- assoc(Assoc, S, S1).
  294
  295%%%%
  296refresh_am(X, Y):- refresh_am(X, Y, 1, _).
  297
  298refresh_am(am(A, B, C), am(A0, B0, C0), N, Assoc):-
  299	refresh_coa(A, A0, N, Assoc),
  300	maplist(assoc(Assoc),[B|C], [B0|C0]).
  301
  302refresh_coa(A, B) :- refresh_coa(A, B, 1,  _).
  303
  304refresh_coa(A, B, N0) :- refresh_coa(A, B, N0, _).
  305
  306refresh_coa(A, B, N, A_list) :- make_assoc(A, N, A_list),
  307	maplist(refresh_state(A_list), A, B).
  308
  309refresh_state(A, (X, S), (Y, T)):- assoc(A, X, Y),
  310	maplist(refresh_pair(A), S, T).
  311
  312refresh_pair(Assoc, (A, S), (A, S1)) :- maplist(assoc(Assoc), S, S1).
  313
  314% ?- join_link([(a, b)], [(a, []), (b, [(1, [a])])], C).
  315% C = [ (a, [ (1, [a, b])]), (b, [ (1, [a, b])])]
  316% ?- join_link([ (a, b), (b, a)], [ (a, []), (b, [ (1, [a])])], C).
  317% C = [ (a, [ (1, [a])]), (b, [ (1, [a])])]
  318% ?- join_link([ (a, b), (b, a)], [ (a, [(1,[b])]), (b, [ (1, [a])])], C).
  319% C = [ (a, [ (1, [a, b])]), (b, [ (1, [a, b])])]
  320
  321join_link(R, C0, C):- foldl(extend_link, R, C0, C).
  322
  323extend_link(P) --> extend_link_right(P),  extend_link_left(P).
  324
  325extend_link_right((X,Y), C0, C):- maplist(extend_link_right(X, Y), C0, C).
  326
  327extend_link_right(X, Y, (A, F0), (A, F)):- maplist(associate(X, Y), F0, F).
  328
  329associate(X, Y, (A, S0), (A, S)):- memberchk(X, S0)
  330	-> contract_merge([Y], S0, S)
  331	;  S = S0.
  332
  333extend_link_left((X, Y), C0, C):- memberchk((Y, F), C0),
  334	extend_coa((X, F), C0, C).
  335
  336propagate_final_state((X, Y), F0, F1):- memberchk(Y, F0), !, union([X], F0, F1).
  337propagate_final_state(_, F, F).
  338
  339%%% automata state minimization
  340% ?- coalgebra:minimum_am(am([ (1, [ (a, [2])]), (2, [ (b, [3])]), (3, [])], 1, [3]), A).
  341% A = am([ (1,[ (a,[2])]), (2,[ (b,[3])]), (3,[])],1,[3]).
  342
  343% ?- qcompile(util(coalgebra)), module(coalgebra).
  344% ?- listing(hybrid_regex_html/3).
  345
  346% ?- call(coalgebra:hybrid_regex_html,*char(alnum)+ +char(digit),svg,_25662).
  347% ?- call(coalgebra:hybrid_regex_html,*char(alnum)+ +char(digit),pdf,_25662).
  348
  349minimum_am(am(C0, I, Final), Am):-
  350    C = [(0,[])|C0],
  351	maplist(fst, C, S),
  352	pairs(S, P0),
  353	maplist(ordered_pair(0), Final, DeadStateConflict0),
  354	basic_conflicts(P0, [], Final, P1, Q),
  355	append(DeadStateConflict0, Q, Q1),
  356	remove_conflicts(P1, Q1,  C, P, _),
  357	maplist(pred([X,[X]]), S, Bs0),
  358	union_find(P, Bs0, Bs1),
  359	remove_dead_state(Bs1, Bs),
  360	quotient_am(am(C0,I,Final), Bs, Am).
  361
  362% ?- basic_conflicts([(1,2),(2,3)], [], [3], X, Y).
  363% X = [ (1, 2)], Y = [ (2, 3)]
  364
  365basic_conflicts([],[], _, [],[]).
  366basic_conflicts([(X,Y)|P0], Q0, F, P, [(X,Y)|Q]):-
  367	(  memberchk(X, F)
  368	-> \+ memberchk(Y, F)
  369	;  memberchk(Y, F)
  370	),
  371	!,
  372	basic_conflicts(P0, Q0, F, P, Q).
  373basic_conflicts([A|P0], Q0, F, [A|P], Q):- basic_conflicts(P0, Q0, F, P, Q).
  374
  375remove_conflicts(P0, Q0, C, P, Q):- select((X,Y), P0, P1),
  376	conflict(X, Y, Q0, C),
  377	!,
  378	remove_conflicts(P1, [(X,Y)|Q0], C, P, Q).
  379remove_conflicts(P, Q,  _, P, Q).
  380
  381conflict(X, Y, Q, C):- memberchk((X, F), C),
  382	memberchk((Y, G), C),
  383	conflict(F, G, Q).
  384
  385conflict(F, G, Q):- select((X,S1), F, F1), select((X,S2), G, G1), !,
  386	(  pair_member(S1, S2, Q) -> true ;  conflict(F1, G1, Q) ).
  387conflict(F, G,Q):-(member((_X,S),F); member((_X,S),G)),
  388	member(Y, S), pair_member0(Y, 0, Q).
  389
  390pair_member(V, W, Q):- member(X, V), member(Y, W), pair_member0(X, Y, Q).
  391
  392pair_member0(X, Y, [(X, Y)|_]).
  393pair_member0(X, Y, [(Y, X)|_]).
  394pair_member0(X, Y, [_|Q]):- pair_member0(X, Y, Q).
  395
  396% ?- union_find([(a,b),(x,y), (x,x), (y, z), (b,c)], [], R).
  397%@ R = [[a,b,c],[x,y,z]].
  398% ?- union_find([(a-b),(x-y), (x-x), (y-z), (b-c)], [], R).
  399%@ R = [[a,b,c],[x,y,z]].
  400
  401union_find([],X,X).
  402union_find([P|R],C,D):- (P = (X,Y); P = (X-Y)), !,
  403	union_find(X, Y, C, C1),
  404	union_find(R,C1,D).
  405
  406%
  407union_find(X,Y,Z,U):-find_cluster(X,Z,C,Z0),
  408	(memberchk(Y, C) -> U=[C|Z0]
  409	; find_cluster(Y, Z0, C0, Z1),
  410	  append(C,C0, C1),
  411	  U=[C1|Z1]
  412	).
  413
  414%
  415remove_dead_state([],[]).
  416remove_dead_state([[0|X]|R],[X|R]):-!.
  417remove_dead_state([X|R],[X|S]):-remove_dead_state(R,S).
  421remove_dead_states(am(M0,I,F), am(M, I, F)):- 	select((X, Ps), M0, M1),
  422	\+ memberchk(X, F),
  423	dead_state(X, Ps),
  424	!,
  425	maplist(delete_target(X), M1, M).
  426remove_dead_states(A, A).
  427
  428delete_target(X, (Y,Ps), (Y,Qs)):- maplist(delete_target0(X), Ps, Qs).
  429
  430delete_target0(X, (Y,Ps), (Y,Qs)):-select(X, Ps, Qs), !.
  431delete_target0(_, Z, Z).
  432
  433dead_state(X, Ps):- forall(member((_,Xs), Ps), (Xs ==[]; Xs=[X])).
  434
  435% quotient dfam
  436
  437quotient_am(am(C0,I0,F0), Bs, am(C, I, F)):-
  438	maplist(quotient_state(Bs), C0, C1),
  439        sort(C1, C2),
  440	remove_duplicates(C2, C),
  441	quotient_map(Bs, I0, I),
  442	maplist(quotient_map(Bs), F0, F1),
  443	sort(F1, F).
  444
  445remove_duplicates([], []).
  446remove_duplicates([(X,Y),(X,_)|C0], C):-!, remove_duplicates([(X,Y)|C0], C).
  447remove_duplicates([(X,Y)|C0], [(X,Y)|C]):- remove_duplicates(C0, C).
  448
  449quotient_map(Bs, X, A):- member(B, Bs), memberchk(X, B), B=[A|_], !.
  450
  451quotient_state(Bs, (X, S), (Y, T)):- quotient_map(Bs, X, Y),
  452	maplist(quotient_snd(Bs), S, T).
  453
  454quotient_snd(Bs, (A, X), (A, Y)):- maplist(quotient_map(Bs), X, Y0),
  455	sort(Y0, Y).
  456
  457%
  458compare_two_regex(A:B, C):- regex_compare(C, A, B).
  459
  460%
  461compare_am(R0, R, E0, E):- compose_am(E0, am(C0, I0, F0)),
  462	compose_am(E, am(C, I, F)),
  463	coalgebra([(I0, I)], product_coa(p(C0, C)), D),
  464	compare_am(R0, R, D, F0, F).
  465
  466%
  467compare_am(R, R, [], _, _):-!.
  468compare_am(R0, R, [((X,Y),_)|D], F, G):-
  469	(    memberchk(X, F)
  470	-> (  memberchk(Y, G)
  471	   -> R1=R0
  472	   ;  subtract(R0, [=, <], R1)
  473	   )
  474	; ( memberchk(Y, G)
  475	   -> subtract(R0, [=, >], R1)
  476	   ;  R1=R0
  477	  )
  478	),
  479        compare_am(R1, R, D, F, G).
  480
  481%
  482order_boole(=, R, true):- memberchk(=, R).
  483order_boole(<, [<], true).
  484order_boole(>, [>], true).
  485order_boole(>=, R, true):- memberchk(>, R); memberchk(=, R).
  486order_boole(=<, R, true):- memberchk(<, R); memberchk(=, R).
  487order_boole(_, _, false):- memberchk(<, _R); memberchk(=, _R).
  488
  489%%%%  tiny routines (selector, etc.) %%%%
  490%%
  491
  492&(X, Y, Z):- append(X, Y, Z).
  493
  494% ?- find_cluster(a, [[a,b],[c,d]], C, X).
  495find_cluster(X,[],[X],[]):-!.
  496find_cluster(X,[Y|Z],Y,Z):- memberchk(X,Y),!.
  497find_cluster(X,[Y|Z],U,[Y|V]):- find_cluster(X,Z,U,V).
  498
  499
  500% ?- field_of_triples([(c, 2, d), (b,1,a)], X).
  501% X = [a, b, c, d]
  502field_of_triples(Ts, F):- unzip(Ts, L, G),
  503	maplist(snd, G, R),
  504	append(L, R, F0),
  505	sort(F0, F).
  506
  507range_of_triples(Ts, R):- maplist(third, Ts, R0), sort(R0, R).
  508
  509make_assoc([],_,[]).
  510make_assoc([(X,_)|R], N, [(X,N)|S] ):- N1 is N+1, make_assoc(R, N1, S).
  511
  512assoc(A, X, Y):- memberchk((X,Y), A).
  513
  514meet(X, Y):- member(A, X), memberchk(A, Y), !.
  515
  516third((_,_,X), X).
  517
  518triple_pair((X,A,Y), (X,[(A,[Y])])).
  519
  520pair_with_empty(X, (X, [])).
  521
  522reverse_triple((X,A,Y), (Y,A,X)).
  523
  524eq_set( F, X, Y) :- member(X = Y, F).
  525
  526comma_set(F, X, Y) :- memberchk((X, Y), F), !.
  527comma_set(_, _, []).
  528
  529pairing_fst(A, (X, [Y]), (X, [(A,Y)])).
  530
  531pairing_snd(A, (X, [Y]), (X, [(Y,A)])).
  532
  533union_image(X, Y):- foldl(union_snd, X, [], Y).
  534
  535union_snd((_, X), A, B):- union(X, A, B).
  536
  537%;; (setq module-query  "qcompile(util(coalgebra)), module(coalgebra).")
  538% ?- qcompile(util(coalgebra)), module(coalgebra).
  539
  540% directory for temporary files  .pdf .png .bb  etc
  541am_dir_path(D):- getenv(home_html_root, C),
  542		atomics_to_string([C, automata], /, D).
  543%
  544am_file_name(am).
  545%
  546compose_sts(E, Sts):- compose_am(E, Am0), am_sts(Am0, Sts).
  547
  548am_sts(am(M0,X,Y), sts(M,X,Y)):-
  549	act_tree(coalgebra:list_triple, M0, M).
  550
  551list_triple([Y, A, X], (X, A, Y)).
  552
  553%%%
  554% ?- coalgebra:arrows([(b, g, c), (a, f, b), (c, h, d), (d, k, b), (c, c, c)]).
  555arrows(Arrows):-autviz_jpg(arrows2dot, Arrows).
  556
  557% ?- qcompile(util(coalgebra)).
  558% ?- module(coalgebra).
  559
  560% ?- trace, gv(a).
  561% ?- gv(a+b+c+d+e).
  562
  563gv(R) :- compose_sts(R, Aut), autviz(Aut).
  564
  565autviz(Aut):-autviz(coalgebra:aut2dot, Aut).
  566
  567%
  568autviz(Pred, Aut):-
  569	absolute_file_name(tmp('DOTTEMP.dot'), DOT),
  570	absolute_file_name(tmp('DOTTEMP.'), M),
  571	file(DOT, write, call(Pred, Aut)),
  572	qshell(dot(-'T'(ps2), -o(M+ps), M+dot);
  573			ps2pdf(M+ps, M+pdf);
  574			open(-a('Preview'), M+pdf)).
  575
  576autviz_jpg(Pred, Aut):-
  577	absolute_file_name(tmp('DOTTEMP.dot'), DOT),
  578	absolute_file_name(tmp('DOTTEMP.'), M),
  579	file(DOT, write, call(Pred, Aut)),
  580	qshell(dot(-'T'(jpg), -o(M+jpg), M+dot); open(-a('Preview'), M+jpg)).
  581
  582states(M, S):- 	maplist(fst, M, L0),
  583	maplist(third, M, L1),
  584	union(L0, L1, S0),
  585	sort(S0, S).
  586
  587automaton(R):- compose_sts(R, sts(M,Ini,Fin)),
  588	states(M, S),
  589	format("Regular expression = ~w~n",[R]),
  590	format("Initial state = ~w~n",[Ini]),
  591	format("List of final states = ~w~n",[Fin]),
  592	format("List of states = ~w~n",[S]),
  593	format("State transitions:~n"),
  594	(  member((A,B,C), M),
  595	   format("    ~w ----- ~w -----> ~w~n",[A,B,C]), fail
  596	;
  597	   true
  598	).
  599
  600%
  601aut2dot(sts(M,Ini,Fin)):-arrows2dot([(dummy, '', Ini)|M], Fin).
  602
  603arrows2dot(Arrows):-arrows2dot(Arrows, []).
  604
  605arrows2dot(Arrows, Fin):-
  606     format("digraph g {~n",[]),
  607     format("rankdir=LR;~n",[]),
  608     format("dummy [shape = none, label = \"\"];~n",[]),
  609     final_in_dot(Fin),
  610     move_in_dot(Arrows),
  611     format("}~n",[]).
  612		/******************************************************
  613		*     convert a  regex to automata  in a pdf file.    *
  614		******************************************************/
  615
  616% ?- regex_coalgebra(".*", X).
  617% ?- coalgebra:show_am(".").
  618% ?- coalgebra:show_am("[a-zA-B]******hello").
  619% ?- coalgebra:show_am("a*").
  620% ?- coalgebra:show_am(".*").
  621% ?- coalgebra:show_am("a*b*c").
  622% ?- coalgebra:show_am("([^abc]+[abc])*").
  623% ?- coalgebra:show_am("[st][0-9][0-9][0-9][0-9][0-9][0-9]*").
  624% ?- coalgebra:show_am("(a|b|c)*").
  625% ?- coalgebra:show_am(a\a).
  626% ?- coalgebra:show_am((*(*(a) + b + *(a) + b + *(a)))).
  627% ?- pac:show_am((*(*(a) + b + *(a) + b + *(a)))).
  628% ?- coalgebra:show_am(* char(alnum)).
  629
  630show_am(Regex) :- regex_to_pdf(Regex, PDF),	qshell(open(PDF)).
  631
  632% ?- regex_to_pdf("a", "~/Desktop/deldel", PDF).
  633regex_to_pdf(Regex, PDF) :- once(regex_to_pdf(Regex, 'DOTTEMP', PDF)).
  634%
  635regex_to_pdf(Regex, Base, PDF):- once(regex_am(Regex, coa(A, I))),
  636	am_finals(coa(A, I), F),
  637	coalgebra_triples(A, B),
  638	automaton_quasi_string(am(B, I, F), Quasi_String),
  639	expand_file_name(Base, [M]),
  640	atomics_to_string([M, ".dot"], DOT),
  641	atomics_to_string([M, ".pdf"], PDF),
  642	file(DOT, write, smash(Quasi_String)),
  643	qshell(dot(-'T'(pdf), -o(PDF), DOT)).
  644
  645			/***********************************
  646			*     handling character escape    *
  647			***********************************/
  648
  649automaton_quasi_string(am(A, Ini, F),
  650	      [		"digraph g {\n",
  651			"rankdir=LR;\n",
  652			IniName,
  653			Label,
  654			Finals,
  655			Moves,
  656			"}\n"
  657	      ])  :-
  658	number_string(Ini, IniName),
  659	atomics_to_string([" [label= \"start( =", IniName, ")\"];\n"], Label),
  660	maplist(triple_elim_dot, A,  Moves),
  661	maplist( pred([X, [Y, " [shape = doublecircle];\n"]] :-
  662		number_string(X, Y)),
  663		F,
  664		Finals).
  665
  666% ?- trace, coalgebra:triple_elim_dot((1, dot([97-98, 100-103]), 2), R).
  667%@ R = ["1", "->", "2", " [label = \"", [91, 97, 93], "\"];\n"] .
  668
  669triple_elim_dot((X, A, Y), [X0, "->", Y0, " [label = ", B, "];\n"])
  670		:-
  671		 number_string(X, X0),
  672		 number_string(Y, Y0),
  673		 adjacent_interval(A, OA, []),
  674		 maplist(interval_exp, OA, A0),
  675 		 term_string(A0, B0, [quoted(false)]),
  676		 term_string(B0, B, [nl(false)]).
  677
  678% ?- coalgebra:simplify_interval([inf-97, 99-sup], X).
  679%@ X = [\=(b)] .
  680% ?- coalgebra:simplify_interval([inf-97, 100-sup], X).
  681%@ X = [=<(a), >=(d)] .
  682
  683%
  684interval_exp(x(X, _), Y):- atom_string(X, Y).
  685% interval_exp(x(X), Y):- atom_string(X, Y).
  686interval_exp(X, Y):- interval_code_char(X, Y), !.
  687interval_exp((inf-sup)\W,  !=(W0))	:- code_to_char_x(W, W0).
  688interval_exp(X\W,  Y\W0):- interval_code_char(X, Y),
  689	code_to_char_x(W, W0).
  690
  691%
  692interval_code_char(x(X, _), Y):- atom_string(X, Y).
  693interval_code_char(inf-sup, '.').
  694interval_code_char(inf-A, =<(A0)):- code_to_char_x(A, A0).
  695interval_code_char(A-sup, >=(A0)):- code_to_char_x(A, A0).
  696interval_code_char(A-A, A0):- code_to_char_x(A, A0).
  697interval_code_char(A-B, A0-B0):- code_to_char_x(A, A0),
  698	code_to_char_x(B, B0).
  699
  700%
  701code_to_char_x(x(X, _), Y):- !, atom_string(X, Y).
  702code_to_char_x(sup, sup):-!.
  703code_to_char_x(X, Y):- char_code(Y0, X),
  704	convert_char(Y0, Y).
  705%
  706printable(A):- member(T, [csym, period, punct, prolog_symbol]),
  707	char_type(A, T),
  708	!.
  709%
  710convert_char('\n', "\\n").
  711convert_char('\t', "\\t").
  712convert_char('\s', "\\ ").
  713convert_char('.', "\\.").
  714convert_char(A, A):- printable(A), !.
  715convert_char(A, B):- char_code(A, C),
  716	number_string(C, B0),
  717	string_concat("code", B0, B).
  718
  719%
  720coalgebra_triples([], []).
  721coalgebra_triples([A-G|R], Triples):-
  722	make_triples(A, G, T),
  723	coalgebra_triples(R, TR),
  724	append(T, TR, Triples).
  725
  726%
  727make_triples(_, [], []).
  728make_triples(A, [B-C|R],[ (A, B, C)|Ts]) :- make_triples(A, R, Ts).
  729make_triples(A, [_|R], Ts):- make_triples(A, R, Ts).
  730%
  731
  732final_in_dot([]).
  733final_in_dot([X|Y]):-format("~w [shape = doublecircle];~n",[X]),
  734	final_in_dot(Y).
  735
  736move_in_dot([]).
  737move_in_dot([(X,A,Y)|Z]):-edge_in_dot(X,A,Y), move_in_dot(Z).
  738
  739edge_in_dot(X,A,Y):- format("\"~w\" -> \"~w\" [label = \"~w\"];~n",[X,Y,A]).
  740
  741% main predicate
  742% generete an automaton for the given regular expression.
  743
  744% ?- trace.
  745% ?- format_list(["a"-[],"b"-[]], "c", "", R).
  746%@ R = "acb".
  747
  748% ?- am_state_summary(char(1-2), 1, 3, [1,2,3], S).
  749am_state_summary(R, Ini, Fin, S, Summary):-
  750	maplist(pred([F-A, S]:- format(string(S), F, A)),
  751		[
  752		"Regular expression = ~w<br>"-[R],
  753		"Initial state = ~w<br>"-[Ini],
  754		"Final states = ~w<br>"-[Fin],
  755		"All states = ~w<br>"-[S]
  756		], Sum),
  757	atomics_to_string(Sum, Summary).
  758
  759reg2html(R, T, URL):-
  760	am_dir_path(D),				% T: output type
  761	am_file_name(F),
  762	phrase((counter(update), obj_get([count(C)])),
  763	       [directory(D), counter_name(atm_cur_id)],  _),
  764	format(codes(OutHtml), "~w/~w~w.html", [D, F, C]),
  765	reg2html(F, D, C, R, T, Body),
  766	flatten(["<html><body>\n", Body, "</body></html>"], H1),
  767	atom_codes(OutNameAtom, OutHtml),
  768	create_file(OutNameAtom, H1),
  769	expand_cgi_path(OutHtml, URL).
  770
  771reg2html(F, D, C, R, T, H) :-  compose_sts(R, sts(M, Ini, Fin)),
  772	states(M, S),
  773	H1 = (format_codes(`<p>Regular expression = ~w</p>`,[R]) &
  774	format_codes(`<p>Initial state = ~w</p>`,[Ini]) &
  775	format_codes(`<p>Final states = ~w</p>`,[Fin]) &
  776	format_codes(`<p>All states = ~w</p>`,[S]) &
  777	format_codes(`<p>State Transitions:</p>~n`,[])),
  778	atomic_list_concat([D, '/', F, C, '.dot'], DotName),
  779	file(DotName, write, coalgebra:aut2dot(sts(M, Ini, Fin))),
  780	formatForHtml(F, D, C, T, Format, Args),
  781	print_moves(M, M1),
  782	format_codes_list(H1 & format_codes(Format, Args) & M1, L, []),
  783	!,
  784	append(L, H).
  785
  786%
  787hybrid_regex_diagram(Regex, T, Out):-	% T: output type; svg/pdf
  788	D = automata,
  789	F = am,
  790	phrase((counter(update), obj:obj_get([count(C)])),
  791	       [directory(D), counter_name(atm_cur_id)],  _),
  792	hybrid_regex_diagram(Regex, F, D, C, T, Out).
  793
  794%
  795hybrid_regex_diagram(R, F, D, C, T, [Summary, Transition, Diagram]) :-
  796	regex_am(R, coa(A, Ini)),
  797	am_finals(coa(A, _), Fin),
  798 	coalgebra_triples(A, M),
  799 	automaton_quasi_string(am(M, Ini, Fin), Quasi_String),
  800	maplist(pred([U-_, U]), A, S),
  801	am_state_summary(R, Ini, Fin, S, Summary),
  802	U = "<p> State Transitions:</p>",
  803	hybrid_print_moves(M, Moves),
  804	atomics_to_string([U, Moves], "<br>\n", Transition),
  805	string_concat(F, C, Base),
  806	string_concat(Base, ".dot", DotFile),
  807	getenv(home_html_root, Dir),
  808	atomics_to_string([Dir,/,D], WorkD),
  809	working_directory(WD_, WorkD),
  810	file(DotFile, write, smash(Quasi_String)),
  811	once(option_table(T, Opt, Ext0, Ext1)),
  812     (  T == pdf  ->
  813		Com = ps2pdf("-sOutputFile=" + Base + "."+ Ext1,
  814				     Base + "."+ Ext0)
  815     ;  Com = 'DUMMY=1'
  816     ),
  817     once(qshell(dot(-'T'(Opt),
  818					 Base + "." + dot,
  819					 -o(Base + "." + Ext0)); Com)),
  820	 working_directory(WD_, WorkD),
  821	 atomics_to_string([D,/, Base, ".", Ext0], Diagram).
  822
  823% ?- apply3(coalgebra:hybrid_regex_html, [*char(alnum)+ +char(digit),svg], R).
  824
  825% char class automata  [2014/06/02]
  826hybrid_regex_html(X, T, URL):-	% T: output type; svg/pdf
  827	am_dir_path(D),
  828	am_file_name(F),
  829	phrase((counter(update), obj:obj_get([count(C)])),
  830	       [directory(D), counter_name(atm_cur_id)],  _),
  831	format(string(HtmlLoc), "~w/~w~w.html", [D, F, C]),
  832	hybrid_regex_html(F, D, C, X, T, Body),
  833	smash(Body, BodyStr),
  834	atomic_list_concat(["<html><body>\n", BodyStr, "</body></html>"], HtmlTag),
  835	create_file(HtmlLoc, HtmlTag),
  836    getenv(host_html_root, R),
  837	atomic_list_concat([R, /, automata, /, F, C, '.html'], URL).
  838
  839% ?- smash0([2, b, c], X).
  840%@ X = "\u0002bc" .
  841hybrid_regex_html(F, D, C, R, T, H) :-
  842	regex_am(R, coa(A, Ini)),
  843	am_finals(coa(A, _), Fin),
  844	length(A, Num),
  845 	coalgebra_triples(A, M),
  846 	automaton_quasi_string(am(M, Ini, Fin), Quasi_String),
  847	maplist(pred([U-_, U]), A, S),
  848	H1 = (format_codes(`<p>Regular expression = ~w</p>`,[R]) &
  849	format_codes(`<p> The number of states = ~d</p>`,[Num]) &
  850	format_codes(`<p> Initial state = ~w</p>`,[Ini]) &
  851	format_codes(`<p> Final states = ~w</p>`,[Fin]) &
  852	format_codes(`<p> All states = ~w</p>`,[S]) &
  853	format_codes(`<p> State Transitions:</p>~n`,[])),
  854	atomic_list_concat([D, '/', F, C, '.dot'], DotName),
  855 	file(DotName, write, smash(Quasi_String)),
  856	formatForHtml(F,D,C,T,Format,Args),			% call sh from inside
  857	hybrid_print_moves(M, M1),
  858	format_codes_list(H1 & format_codes(Format,Args) & M1, L, []),
  859	!,
  860	append(L, H).
  861
  862%
  863format_codes_list(X&Y, L, M):- !, format_codes_list(X, L, L0),
  864		   format_codes_list(Y, L0, M).
  865format_codes_list([], L, L).
  866format_codes_list([X|Y], [[X|Y]|L], L).
  867format_codes_list(P, [V|L], L):- call(P, V).
  868
  869%
  870option_table(pdf, ps2, ps, pdf).
  871option_table(png, 'png:gd', png, png).
  872option_table(X, X, X, X).
  873
  874formatForHtml(F,D,C,X,Format,[F,C,X]) :-
  875        img_frame(Format),
  876        atomic_list_concat([D, (/), F, C], Base),
  877	once(option_table(X, Opt, Ext0, Ext1)),
  878     (  X == pdf
  879     -> Com = ps2pdf(`-sOutputFile=`+ Base+ `.`+ Ext1,
  880		     Base+ `.`+ Ext0)
  881     ;  Com = 'DUMMY=1'
  882     ),
  883         once(qshell(dot(-'T'(Opt), Base+ `.` + dot,
  884		  -o(Base + `.` + Ext0)); Com)).
  885
  886img_frame(X) :- flatten([ `<p><div `,
  887	  `id='diagram' `,
  888	  `style='border : solid 2px #ff0000; `,
  889	  `width : 1600px; `,			% was 600px
  890	  `height : 500px; `,			% was 300px
  891	  `overflow : auto; '><br/>`,
  892	  `<img src="~w~w.~w"/>`,
  893	  `</div></p>~n`
  894	 ], X).
  895
  896% ?- coalgebra:hybrid_print_moves([(1, [97-97], 2)], R).
  897% ?- coalgebra:hybrid_print_moves([(1, [97-97], 2), (1, [97-97], 2), (1, [97-97], 2)], R).
  898
  899hybrid_print_moves(M, H):-
  900	maplist(pred([(X, A, Y), (X, B, Y)]:-
  901	       maplist(interval_code_char, A, B)),
  902		M, M0),
  903	maplist(print_move, M0, H1),
  904	atomics_to_string(H1, "<br>", H).
  905
  906print_move((X,A,Y), H):-
  907	format(string(H), "   ~w----~w--->~w~n" , [X,A,Y]).
  908
  909
  910%  ?- symbols(a + b, X).
  911%  ?- symbols(a + b, X)
  912%  X = [a, b].
  913
  914symbols(A, S) :- collect_symbols(A, S0), sort(S0, S).
  915
  916symbols_(A, [A]):- atomic(A), !.
  917symbols_(E, S):- E =..[Op|As],
  918		length(As,L),
  919	        signature(Sig),
  920		memberchk(Op/L, Sig),
  921		maplist(symbols_, As, Bs),
  922		append(Bs, S).
  923symbols_(A = [A]).
  924
  925% ?- pac:expand_exp('`'([]), a, V, [], G, P, []).
  926
  927% ?- trace, pac: expand_kind_rule(s, [], [], epsilon = '`'([]), Y).
  928%@ Y =  (s(epsilon, []):-!) .
  929
  930% ?- spy(ekind).
  931%@ % Spy point on pac:ekind/0
  932%@ true.
  933
  934
  935
  936collect_symbols(epsilon,[]):-! .
  937collect_symbols(empty,[]):-! .
  938collect_symbols(E,A1):-(E=..[Op|As],length(As,L),L>0,signature(Sig),memberchk(Op/L,Sig)),!,maplist(collect_symbols,As,A2),append(A2,A1) .
  939collect_symbols(A,[A]):-! .
  940
  941
  942% ?- coalgebra:ya_symbols(a, X).
  943% ?- listing(preprocess_complement).
  944
  945preprocess_complement(A, X, Y):-
  946	( A== []
  947	->	U = epsilon
  948	;	vector_term(+, A, A0),
  949		U= *(A0)
  950	),
  951	elim_unary_minus(U, X, Y).
  952
  953%
  954elim_unary_minus(A, -(B), A\C):- !, elim_unary_minus(A, B, C).
  955elim_unary_minus(A, B, C):- compound(B), B =..[Op|Bs],
  956		length(Bs,L),
  957		L>0,
  958	        signature(Sig),
  959		memberchk(Op/L, Sig),
  960		!,
  961		maplist(elim_unary_minus(A), Bs, Cs),
  962		C =..[Op|Cs].
  963elim_unary_minus(_, B, B).
  964
  965% ?- gv(a).
  966
  967% ?- vector_term(+, [a,b,c], V).
  968% ?- coalgebra:elim_unary_minus(epsilon, a, X).
  969%@ X = a.
  970% ?- coalgebra:elim_unary_minus(universe, -(a + (-b)), X).
  971%@ X = (universe\a+ (universe\b)).
  972
  973complement_subtract(U, -X, U\X).
  974
  975is_unary_minus_term(-(_))