1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: jan@swi-prolog.org 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2026, SWI-Prolog Solutions b.v. 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(prolog_table_utils, 36 [ table_statistics/0, % Statistics 37 table_statistics/1, % ?Variant 38 table_statistics_by_predicate/0, 39 table_statistics_by_predicate/1, % +Options 40 table_statistics/2, % ?Stat, -Value 41 table_statistics/3, % ?Variant, ?Stat, -Value 42 tstat/2, % ?Stat, ?Top 43 tstat/3, % ?Variant, ?Stat, ?Top 44 tdump/0, % Dump tables 45 tdump/1, % :Goal 46 tdump/2, % :Goal, +Options 47 tidg/0, 48 tidg/1, % :Goal 49 summarize_idg/0, 50 summarize_idg/1 % +Top 51 ]). 52:- autoload(library(lists), [member/2]). 53:- autoload(library(aggregate), [aggregate_all/3]). 54:- autoload(library(ansi_term), [ansi_format/3]). 55:- autoload(library(apply), [exclude/3, maplist/2]). 56:- autoload(library(dif), [dif/2]). 57:- autoload(library(error), [domain_error/2]). 58:- autoload(library(option), [option/3, option/2]). 59:- autoload(library(prolog_code), [pi_head/2]). 60:- autoload(library(solution_sequences), [limit/2, order_by/2]). 61:- autoload(library(varnumbers), [numbervars/1]). 62 63:- meta_predicate 64 tdump(), 65 tdump(, ), 66 idg(), 67 summarize_idg(), 68 table_statistics(), 69 table_statistics(, , ), 70 tstat(, , ).
78summary_table_width(55).The values for Stat are:
1 means no duplicates. 2 means for every answer there
was (on everage) a duplicate generated.1. A low number
implies that a large amount of differently shaped data
is included in the answer tries.invalidated this implies that dependent nodes
of the IDG were reevaluated to the same answer set.116table_statistics(Stat, Value) :- 117 table_statistics(_:_, Stat, Value). 118 119table_statistics(Variant, Stat, Value) :- 120 ( var(Stat) 121 -> table_statistics_(Variant, Stat, Value) 122 ; table_statistics_(Variant, Stat, Value) 123 -> true 124 ). 125 126table_statistics_(Variant, tables, NTables) :- 127 aggregate_all(count, table(Variant, _), NTables). 128table_statistics_(Variant, Stat, Total) :- 129 variant_trie_stat(Stat, _What), 130 \+ hidden_stat(Stat, Variant), 131 ( avg(Stat) 132 -> aggregate_all(sum(Ratio)+count, 133 variant_stat(Stat, Variant, Ratio), 134 Sum+Count), 135 Count > 0, 136 Total is Sum/Count 137 ; aggregate_all(sum(Count), variant_stat(Stat, Variant, Count), Total) 138 ). 139 (variables, _). 141hidden_stat(lookup, _). 142hidden_stat(invalidated, Variant) :- 143 callable(Variant), 144 \+ predicate_property(Variant, tabled(incremental)). 145hidden_stat(reevaluated, Variant) :- 146 callable(Variant), 147 \+ predicate_property(Variant, tabled(incremental)). 148 149avg(space_ratio). 150avg(duplicate_ratio).
158table_statistics :-
159 ( ( '$tbl_global_variant_table'(Table),
160 call_table_properties(shared, Table)
161 ; '$tbl_local_variant_table'(Table),
162 call_table_properties(private, Table)
163 ),
164 fail
165 ; true
166 ),
167 ansi_format([bold], 'Summary of answer trie statistics:', []),
168 nl,
169 table_statistics_(_:_, [tables(false)]).176table_statistics(Variant) :- 177 table_statistics_(Variant, []). 178 179table_statistics_(Variant, Options) :- 180 table_statistics_dict(Variant, Dict), 181 print_table_statistics(Dict, Options). 182 183table_statistics_dict(Variant, Dict) :- 184 findall(Stat-Value, table_statistics(Variant, Stat, Value), Pairs), 185 dict_create(Dict, table_stat, [variant-Variant|Pairs]). 186 187print_table_statistics(Dict, Options) :- 188 summary_table_width(DefWidth), 189 option(width(Width), Options, DefWidth), 190 ( option(tables(false), Options) 191 -> dif(Stat, tables) 192 ; true 193 ), 194 ( option(header(true), Options) 195 -> print_table_predicate_header(Dict.variant, [width(Width)|Options]) 196 ; true 197 ), 198 ( variant_trie_stat0(Stat, What), 199 Value = Dict.get(Stat), 200 ( integer(Value) 201 -> format(' ~w ~`.t ~D~*|~n', [What, Value, Width]) 202 ; format(' ~w ~`.t ~2f~*|~n', [What, Value, Width]) 203 ), 204 fail 205 ; true 206 ). 207 208print_table_predicate_header(Pred, Options) :- 209 option(width(Width), Options), 210 Pred = M:Head, 211 tflags(Pred, Flags), 212 functor(Head, Name, Arity), 213 format('~n~`\u2015t~*|~n', [Width]), 214 format('~t~p~t~w~*|~n', [M:Name/Arity, Flags, Width]), 215 format('~`\u2015t~*|~n', [Width]). 216 217tflags(Pred, Flags) :- 218 findall(F, tflag(Pred, F), List), 219 atomic_list_concat(List, Flags). 220 221tflag(Pred, Flag) :- 222 predicate_property(Pred, tabled(How)), 223 tflag_name(How, Flag). 224 225tflag_name(variant, 'V'). 226tflag_name(subsumptive, 'S'). 227tflag_name(shared, 'G'). 228tflag_name(incremental, 'I'). 229 230 231variant_trie_stat0(tables, "Answer tables"). 232variant_trie_stat0(Stat, What) :- 233 dif(Stat, tables), 234 variant_trie_stat(Stat, What). 235 236call_table_properties(Which, Trie) :- 237 ansi_format([bold], 'Statistics for ~w call trie:', [Which]), 238 nl, 239 summary_table_width(Width), 240 ( call_trie_property_name(P, Label, Value), 241 atrie_prop(Trie, P), 242 ( integer(Value) 243 -> format(' ~w ~`.t ~D~*|~n', [Label, Value, Width]) 244 ; format(' ~w ~`.t ~1f~*|~n', [Label, Value, Width]) 245 ), 246 fail 247 ; true 248 ). 249 250call_trie_property_name(value_count(N), 'Number of tables', N). 251call_trie_property_name(size(N), 'Memory for call trie', N). 252call_trie_property_name(space_ratio(N), 'Space efficiency', N).
tables, the
number of answer tables. See table_statistics/2 for a list
of values for Key.270table_statistics_by_predicate :- 271 Pred = _:_, 272 summary_table_width(Width), 273 ( tabled_predicate_with_tables(Pred), 274 print_table_predicate_header(Pred, [width(Width)]), 275 table_statistics(Pred), 276 fail 277 ; true 278 ). 279 280table_statistics_by_predicate(Options) :- 281 option(order_by(OrderBy), Options, tables), 282 option(top(Top), Options, infinite), 283 option(module(M), Options, _), 284 Pred = (M:_), 285 findall(Dict, 286 ( tabled_predicate_with_tables(Pred), 287 table_statistics_dict(Pred, Dict) 288 ), 289 Dicts), 290 exclude(has_no_key(OrderBy), Dicts, Dicts1), 291 ( integer(Top), Top < 0 292 -> Order = @=<, 293 TopN is -Top 294 ; Order = @>=, 295 TopN is Top 296 ), 297 sort(OrderBy, Order, Dicts1, Sorted), 298 forall(limit(TopN, member(Dict, Sorted)), 299 print_table_statistics(Dict, [header(true)|Options])). 300 301has_no_key(Key, Dict) :- 302 \+ _ = Dict.get(Key). 303 304tabled_predicate_with_tables(Pred) :- 305 Pred = _:_, 306 predicate_property(Pred, tabled), 307 \+ predicate_property(Pred, imported_from(_)), 308 \+ \+ table(Pred, _).
ret(...) to the table for each answer, where each
variable is an argument of the ret(...) term. The arguments
are placed in depth-first lef-right order they appear in the
variant. Optimal behaviour of the trie is achieved if the
variance is as much as possible to the rightmost arguments.
Poor allocation shows up as a low space_ratio statistics.Below are some examples
340% - Find the tables with poor space behaviour (bad) 341% 342% ?- tstat(space_ratio, -10). 343% 344% - Find the tables with a high number of duplicates (good, but 345% if the number of duplicates can easily be reduced a lot it 346% makes your code faster): 347% 348% ?- tstat(duplicate_ratio, 10). 349 350tstat(Stat, Top) :- 351 tstat(_:_, Stat, Top). 352tstat(Variant, Stat, Top) :- 353 variant_trie_stat(Stat, What), 354 top(Top, Count, Limit, Dir, Order), 355 findall(Variant-Count, 356 limit(Limit, order_by([Order], variant_stat(Stat, Variant, Count))), 357 Pairs), 358 write_variant_table('~w ~w count per variant'-[Dir, What], Pairs). 359 360top(Top, Var, 10, "Top", desc(Var)) :- 361 var(Top), !. 362top(Top, Var, Top, "Top", desc(Var)) :- 363 Top >= 0, !. 364top(Top, Var, Limit, "Bottom", asc(Var)) :- 365 Limit is -Top. 366 367variant_stat(Stat, V, Count) :- 368 variant_trie_stat(Stat, _, Count, Property), 369 table(V, T), 370 atrie_prop(T, Property). 371 372atrie_prop(T, size(Bytes)) :- 373 '$trie_property'(T, size(Bytes)). 374atrie_prop(T, compiled_size(Bytes)) :- 375 '$trie_property'(T, compiled_size(Bytes)). 376atrie_prop(T, value_count(Count)) :- 377 '$trie_property'(T, value_count(Count)). 378atrie_prop(T, space_ratio(Values/Nodes)) :- 379 '$trie_property'(T, value_count(Values)), 380 Values > 0, 381 '$trie_property'(T, node_count(Nodes)). 382atrie_prop(T, lookup_count(Count)) :- 383 '$trie_property'(T, lookup_count(Count)). 384atrie_prop(T, duplicate_ratio(Ratio)) :- 385 '$trie_property'(T, value_count(Values)), 386 Values > 0, 387 '$trie_property'(T, lookup_count(Lookup)), 388 Ratio is (Lookup - Values)/Values. 389atrie_prop(T, gen_call_count(Count)) :- 390 '$trie_property'(T, gen_call_count(Count)). 391atrie_prop(T, invalidated(Count)) :- 392 '$trie_property'(T, invalidated(Count)). 393atrie_prop(T, reevaluated(Count)) :- 394 '$trie_property'(T, reevaluated(Count)). 395atrie_prop(T, deadlock(Count)) :- 396 '$trie_property'(T, deadlock(Count)), 397 Count > 0. 398atrie_prop(T, wait(Count)) :- 399 '$trie_property'(T, wait(Count)), 400 Count > 0. 401atrie_prop(T, variables(Count)) :- 402 '$tbl_table_status'(T, _Status, _Wrapper, Skeleton), 403 functor(Skeleton, ret, Count). 404 405variant_trie_stat(Stat, What) :- 406 ( variant_trie_stat(Stat, What, _, _) 407 *-> true 408 ; domain_error(tstat_key, Stat) 409 ). 410 411variant_trie_stat(answers, "Number of answers", 412 Count, value_count(Count)). 413variant_trie_stat(duplicate_ratio,"Duplicate answer ratio", 414 Ratio, duplicate_ratio(Ratio)). 415variant_trie_stat(space_ratio, "Space efficiency", 416 Ratio, space_ratio(Ratio)). 417variant_trie_stat(complete_call, "Calls to completed tables", 418 Count, gen_call_count(Count)). 419variant_trie_stat(invalidated, "Times the tables were invalidated", 420 Count, invalidated(Count)). 421variant_trie_stat(reevaluated, "Times the tables were reevaluated", 422 Count, reevaluated(Count)). 423variant_trie_stat(space, "Memory usage for answer tables", 424 Bytes, size(Bytes)). 425variant_trie_stat(compiled_space, "Memory usage for compiled answer tables", 426 Bytes, compiled_size(Bytes)). 427variant_trie_stat(variables, "Number of variables in answer skeletons", 428 Count, variables(Count)). 429variant_trie_stat(wait, "Times table was waited for", 430 Count, wait(Count)). 431variant_trie_stat(deadlock, "Times table was involved in a deadlock", 432 Count, deadlock(Count)).
436write_variant_table(Format-Args, Pairs) :- 437 format(string(Title), Format, Args), 438 tty_size(_, Cols), 439 W is Cols - 8, 440 format('~`\u2015t~*|~n', [W]), 441 format('~t~w~t~*|~n', [Title, W]), 442 format('~`\u2015t~*|~n', [W]), 443 maplist(write_variant_stat(W), Pairs). 444 445write_variant_stat(W, V-Stat) :- 446 \+ \+ ( numbervars(V, 0, _, [singletons(true)]), 447 ( integer(Stat) 448 -> format('~p ~`.t ~D~*|~n', [V, Stat, W]) 449 ; format('~p ~`.t ~2f~*|~n', [V, Stat, W]) 450 ) 451 ). 452 453table(M:Variant, Trie) :- 454 '$tbl_variant_table'(VariantTrie), 455 trie_gen(VariantTrie, M:Variant, Trie). 456 457 458 /******************************* 459 * DUMP TABLES * 460 *******************************/
local or global.true, also show reset (fresh) global tables. These
are tables that have been abolished.476tdump :- 477 tdump(_:_). 478tdump(M:Goal) :- 479 tdump(M:Goal, []). 480 481tdump(M:Goal, Options) :- 482 option(scope(Scope), Options, _), 483 option(limit(Limit), Options, 100), 484 ( table(Scope, M:Goal, Trie), 485 '$tbl_table_status'(Trie, Status, M:Variant, Skeleton), 486 M:'$table_mode'(Head0, Variant, Moded), 487 Head = M:Head0, 488 ( option(reset(true), Options) 489 -> true 490 ; \+ (Scope == global, Status == fresh) 491 ), 492 ansi_format(comment, 'Trie for variant ', []), 493 pflags(Variant, Flags), 494 format('~s ', [Flags]), 495 print_variant(Head), 496 Answer = Head, 497 '$tbl_trienode'(Reserved), 498 ( Moded == Reserved 499 -> findall(Answer-Delay, 500 '$tbl_answer'(Trie, Skeleton, Delay), Pairs), 501 ExtraProp = '' 502 ; findall(Answer-Delay, 503 '$tbl_answer'(Trie, Skeleton, Moded, Delay), Pairs), 504 ExtraProp = 'moded, ' 505 ), 506 sort(1, @<, Pairs, Sorted), 507 length(Sorted, Count), 508 status_color(Status, Color), 509 ansi_format(comment, ' (~p,', [Scope]), 510 ansi_format(Color, ' ~p', [Status]), 511 ansi_format(comment, ', ~w~D answers)~n', [ExtraProp, Count]), 512 ( Count == 0 513 -> ansi_format(warning, ' (empty)~n', []) 514 ; forall(limit(Limit, member(Ans, Sorted)), 515 dump_answer(M, Ans)) 516 ), 517 fail 518 ; true 519 ). 520 521status_color(invalid, warning) :- !. 522status_color(_, comment). 523 524 525table(local, Variant, Trie) :- 526 '$tbl_local_variant_table'(VariantTrie), 527 trie_gen(VariantTrie, Variant0, Trie), 528 subsumes_term(Variant, Variant0), 529 Variant = Variant0. 530table(global, Variant, Trie) :- 531 '$tbl_global_variant_table'(VariantTrie), 532 trie_gen(VariantTrie, Variant0, Trie), 533 subsumes_term(Variant, Variant0), 534 Variant = Variant0. 535 536print_variant(Head) :- 537 term_attvars(Head, []), 538 !, 539 \+ \+ ( numbervars(Head, 0, _), 540 ansi_format(code, '~p', [Head]) 541 ). 542print_variant(Head) :- 543 copy_term(Head, Copy, Constraints), 544 numbervars(Copy+Constraints, 0, _), 545 format('~p', [Copy]), 546 forall(member(C, Constraints), 547 ansi_format(fg(blue), ', ~p', [C])). 548 549dump_answer(M, Answer0-true) :- 550 !, 551 unqualify(Answer0, M, Answer), 552 \+ \+ print_answer(Answer). 553dump_answer(M, Answer0-Condition) :- 554 unqualify(Answer0, M, Answer), 555 unqualify(Condition, M, SimpleCondition), 556 \+ \+ ( numbervars(Answer+SimpleCondition, 0, _), 557 format(' ~p', [Answer]), 558 ansi_format(bold, ' :- ', []), 559 ansi_format(fg(cyan), '~p~n', [SimpleCondition]) 560 ). 561 562print_answer(Answer) :- 563 term_attvars(Answer, []), 564 !, 565 numbervars(Answer, 0, _), 566 format(' ~p~n', [Answer]). 567print_answer(Answer) :- 568 copy_term(Answer, Copy, Constraints), 569 numbervars(Copy+Constraints, 0, _), 570 format(' ~p', [Copy]), 571 forall(member(C, Constraints), 572 ansi_format(fg(blue), ', ~p', [C])), 573 nl. 574 575unqualify(Var, _M, Var) :- 576 var(Var), 577 !. 578unqualify((A0,B0), M, (A,B)) :- 579 !, 580 unqualify(A0, M, A), 581 unqualify(B0, M, B). 582unqualify((A0;B0), M, (A;B)) :- 583 !, 584 unqualify(A0, M, A), 585 unqualify(B0, M, B). 586unqualify(tnot(A0), M, tnot(A)) :- 587 !, 588 unqualify(A0, M, A). 589unqualify((M1:Variant)/ModeArgs, M, Goal) :- 590 !, 591 M1:'$table_mode'(G0, Variant, ModeArgs), 592 unqualify(M1:G0, M, Goal). 593unqualify(M:G, M, G) :- 594 !. 595unqualify(G, _, G).
603tidg :- 604 ansi_format(comment, 605 '% Node1 [falsecount] (affects -->) Node1 [falsecount]~n', []), 606 forall(idg(t(_:From,FFC,FAC), affected, t(_:To,TFC,TAC)), 607 \+ \+ ( numbervars(From), 608 numbervars(To), 609 print_edge(From, FFC,FAC, To, TFC,TAC) 610 )). 611 612tidg(M:Node) :- 613 ansi_format(comment, 614 '% Node1 [falsecount] (affects -->) Node1 [falsecount]~n', []), 615 ansi_format([bold], 'Affected nodes~n', []), 616 forall(idg(t(M:Node,FFC,FAC), affected, t(_:To,TFC,TAC)), 617 \+ \+ ( numbervars(Node), 618 numbervars(To), 619 print_edge(Node, FFC,FAC, To, TFC,TAC) 620 )), 621 ansi_format([bold], 'Dependent nodes~n', []), 622 forall(idg(t(_:From,FFC,FAC), affected, t(M:Node,TFC,TAC)), 623 \+ \+ ( numbervars(From), 624 numbervars(Node), 625 print_edge(From, FFC,FAC, Node, TFC,TAC) 626 )). 627 628 629print_edge(From, FFC,FAC, To, TFC,TAC) :- 630 format(' '), 631 print_node(From, FFC,FAC), 632 format(' --> '), 633 print_node(To, TFC,TAC), 634 nl. 635 636print_node(Variant, Falsecount, AnswerCount) :- 637 pflags(Variant, Flags), 638 format('~s ', [Flags]), 639 ansi_format(code, '~p', [Variant]), 640 format(' '), 641 ( Falsecount == 0 642 -> ansi_format(comment, '[0]', []) 643 ; ansi_format([bg(red),fg(white)], '[~w]', [Falsecount]) 644 ), 645 print_answer_count(AnswerCount). 646 647print_answer_count(answers(Count)) => 648 format(' (~Da)', [Count]). 649print_answer_count(clauses(Count)) => 650 format(' (~Dc)', [Count]). 651 652pflags(Variant, Flags) :- 653 findall(F, flag(Variant, F), Flags). 654 655flag(Variant, Flag) :- 656 ( pflag(Variant, dynamic, 'D', Flag) 657 ; pflag(Variant, incremental, 'I', Flag) 658 ; pflag(Variant, monotonic, 'M', Flag) 659 ). 660 661pflag(Variant, Property, Char, Flag) :- 662 ( predicate_property(Variant, Property) 663 -> Flag = Char 664 ; Flag = ' ' 665 ). 666 667idg(t(FM:From,FFC,FAC), Dir, t(TM:To,TFC,TAC)) :- 668 '$tbl_variant_table'(VTrie), 669 trie_gen(VTrie, FM:FVariant, ATrie), 670 ( FM:'$table_mode'(From1, FVariant, _FModed) 671 -> true 672 ; From1 = FVariant % dynamic incremental/monotonic 673 ), 674 subsumes_term(From, From1), 675 From = From1, 676 fc(ATrie, From, FFC,FAC), 677 '$idg_edge'(ATrie, Dir, DepTrie), 678 '$tbl_table_status'(DepTrie, _Status, TM:TVariant, _Return), 679 TM:'$table_mode'(To1, TVariant, _TModed), 680 subsumes_term(To, To1), 681 To = To1, 682 fc(DepTrie, To, TFC,TAC). 683 684fc(ATrie, Variant, FC, AC) :- 685 ( predicate_property(Variant, tabled) 686 -> trie_property(ATrie, value_count(C)), 687 AC = answers(C) 688 ; aggregate_all(count, clause(Variant,_), C), 689 AC = clauses(C) 690 ), 691 ( '$idg_falsecount'(ATrie, FC0) 692 -> ( '$idg_forced'(ATrie) 693 -> FC = FC0/'F' 694 ; FC = FC0 695 ) 696 ; FC = 0 697 ).
statistics(summarize_idg)704:- module_transparent 705 summarize_idg/0. 706 707summarize_idg :- 708 context_module(M), 709 summarize_idg(infinite, M). 710 711summarize_idg(M:Top) :- 712 summarize_idg(Top, M). 713 714summarize_idg(Top, M) :- 715 tty_width(Width), 716 header('Interior Nodes (Tabled Subgoals)', Width), 717 format('Predicate~t #idg nodes~*|~n', [Width]), 718 format('~`\u2015t~*|~n', [Width]), 719 forall(limit(Top, 720 order_by([desc(Count),asc(PI)], 721 interior_nodes(_:_, M, PI, Count))), 722 format('~q ~`.t ~D~*|~n', [PI, Count, Width])), 723 nl, 724 ColR is Width - 10, 725 header('Leaf Nodes (Calls to Dynamic Predicates)', Width), 726 format('Predicate~t #idg nodes~*|~t#facts~*|~n', [ColR, Width]), 727 format('~`\u2015t~*|~n', [Width]), 728 forall(limit(Top, 729 order_by([desc(Count),desc(Facts),asc(PI)], 730 leaf_nodes(_:_, M, PI, Count, Facts))), 731 format('~q ~`.t ~D~*| ~`.t ~D~*|~n', 732 [PI, Count, ColR, Facts, Width])). 733 734interior_nodes(Variant, M, PI, Count) :- 735 predicate_property(Variant, tabled(incremental)), 736 \+ predicate_property(Variant, imported_from(_)), 737 idg_node_count(Variant, Count), 738 pi_head(QPI, Variant), 739 unqualify_pi(QPI, M, PI). 740 741leaf_nodes(Variant, M, PI, Count, Facts) :- 742 predicate_property(Variant, dynamic), 743 predicate_property(Variant, incremental), 744 \+ predicate_property(Variant, imported_from(_)), 745 predicate_property(Variant, number_of_clauses(Facts)), 746 idg_node_count(Variant, Count), 747 pi_head(QPI, Variant), 748 unqualify_pi(QPI, M, PI). 749 750 751idg_node_count(Variant, Count) :- 752 aggregate_all(count, 753 ( '$tbl_variant_table'(VTrie), 754 trie_gen(VTrie, Variant, _ATrie) 755 ), 756 Count). 757 758unqualify_pi(M:PI, M, PI) :- !. 759unqualify_pi(PI, _, PI). 760 761tty_width(W) :- 762 catch(tty_size(_, TtyW), _, fail), 763 !, 764 W is max(60, TtyW - 8). 765tty_width(60). 766 767header(Title, Width) :- 768 format('~N~`\u2015t~*|~n', [Width]), 769 ansi_format([bold], '~t~w~t~*|', [Title,Width]), 770 nl
Table inspection and statistics utilities
This library provides tools intended to be used at the interactive toplevel for inspecting tables, table dependencies and table statistics. */