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