View source with raw comments or as raw
    1/*  Part of sCASP
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        jan@swi-prolog.org
    5    Copyright (c)  2021, SWI-Prolog Solutions b.v.
    6    All rights reserved.
    7
    8    Redistribution and use in source and binary forms, with or without
    9    modification, are permitted provided that the following conditions
   10    are met:
   11
   12    1. Redistributions of source code must retain the above copyright
   13       notice, this list of conditions and the following disclaimer.
   14
   15    2. Redistributions in binary form must reproduce the above copyright
   16       notice, this list of conditions and the following disclaimer in
   17       the documentation and/or other materials provided with the
   18       distribution.
   19
   20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   21    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   23    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   24    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   25    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   26    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   27    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   28    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   30    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31    POSSIBILITY OF SUCH DAMAGE.
   32*/
   33
   34:- module(scasp_model,
   35          [ canonical_model/2,          % +RawModel, -Canonical
   36            unqualify_model/3,          % +ModelIn, +Module, -ModelOut
   37            print_model/2               % :Model, +Options
   38          ]).   39:- use_module(library(apply)).   40:- use_module(library(lists)).   41:- use_module(library(pairs)).   42
   43:- use_module(common).   44:- use_module(modules).   45:- use_module(output).   46
   47:- meta_predicate
   48    canonical_model(:, -),
   49    print_model(:, +).   50
   51:- multifile
   52    model_hook/2.

sCASP model handling

*/

 canonical_model(:RawModel, -Canonical)
   61canonical_model(M:Model, CanModel) :-
   62    flatten(Model, FlatModel),
   63    exclude(nonmodel_term, FlatModel, Model1),
   64    sort(Model1, Unique),
   65    maplist(raise_negation, Unique, Raised),
   66    filter_shown(M, Raised, Filtered),
   67    sort_model(Filtered, Sorted),
   68    simplify_model(Sorted, CanModel).
   69
   70nonmodel_term(abducible(_)).
   71nonmodel_term(proved(_)).
   72nonmodel_term(chs(_)).
   73nonmodel_term(o_nmr_check).
   74nonmodel_term(not(X)) :-
   75    nonvar(X),
   76    !,
   77    nonmodel_term(X).
   78nonmodel_term(Term) :-
   79    functor(Term, Name, _),
   80    (   sub_atom(Name, 0, _, _, 'o_')
   81    ->  true
   82    ;   sub_atom(Name, _, _, 0, '$')
   83    ).
 filter_shown(+Module, +Model, -Shown) is det
Handle the show/1 directives. All terms are shown for a target module if pr_show_predicate/1 is not defined for that module. Otherwise the terms associated with the module are filtered using pr_show_predicate/1.
   92filter_shown(M, Model, Shown) :-
   93    maplist(tag_module(M), Model, Tagged),
   94    maplist(arg(1), Tagged, Modules),
   95    sort(Modules, Unique),
   96    include(has_shown, Unique, Filter),
   97    (   Filter == []
   98    ->  Shown = Model
   99    ;   convlist(do_show(Filter), Tagged, Shown)
  100    ).
  101
  102tag_module(M, Term, t(Q, Unqualified, Term)) :-
  103    model_term_module(M:Term, Q),
  104    unqualify_model_term(Q, Term, Unqualified).
  105
  106has_shown(Module) :-
  107    clause(Module:pr_show_predicate(_), _),
  108    !.
  109
  110do_show(Filter, t(M,Unqualified,Term), Term) :-
  111    (   memberchk(M, Filter)
  112    ->  M:pr_show_predicate(Unqualified)
  113    ;   true
  114    ).
 sort_model(+ModelIn, -Sorted) is det
Sort the model by literal, getting affirming and denying knowledge about a literal together. If multiple terms about the same literal appear they are ordered:
  1. positive
  2. not(positive)
  3. -positive
  4. not(-positive).
  127sort_model(ModelIn, Sorted) :-
  128    map_list_to_pairs(literal_key, ModelIn, Pairs),
  129    keysort(Pairs, KSorted),
  130    pairs_values(KSorted, Sorted).
  131
  132literal_key(Term, Literal-Flags) :-
  133    literal_key(Term, Literal, 0, Flags).
  134
  135literal_key(not(X), Key, F0, F) =>
  136    literal_key(X, Key, F0, F1),
  137    F is F1+0x1.
  138literal_key(-(X), Key, F0, F) =>
  139    literal_key(X, Key, F0, F1),
  140    F is F1+0x2.
  141literal_key(X, Key, F0, F) =>
  142    Key = X,
  143    F = F0.
 simplify_model(+ModelIn, -ModelOut) is det
Remove model terms that are entailed by other model terms.
  149simplify_model([not(X0),-X1|T0], M), X0 == X1 =>
  150    M = [-X1|M0],
  151    simplify_model(T0, M0).
  152simplify_model([X0, not(-(X1))|T0], M), X0 == X1 =>
  153    M = [X0|M0],
  154    simplify_model(T0, M0).
  155simplify_model([H|T0], M) =>
  156    M = [H|M0],
  157    simplify_model(T0, M0).
  158simplify_model([], M) =>
  159    M = [].
 unqualify_model(+ModelIn, +Module, -ModelOut) is det
Restore the model relation to modules.
  165unqualify_model(Model0, Module, Model) :-
  166    maplist(unqualify_model_term(Module), Model0, Model).
 print_model(:Model, +Options) is det
Print the model in aligned columns. Options processed:
width(Width)
Assumed terminal width. Default from tty_size/2 or 80.

Model terms are printed in columns. E.g., for a 10 atom model and 4 columns we get:

   1  4  7  10
   2  5  8
   3  6  9
  184:- if(\+current_predicate(tty_size/2)).  185tty_size(25,80).
  186:- endif.  187
  188print_model(Model, Options) :-
  189    model_hook(Model, Options),
  190    !.
  191print_model(_:Model, Options) :-
  192    (   option(width(Width), Options)
  193    ->  true
  194    ;   catch(tty_size(_, Width), _, Width = 80)
  195    ),
  196    layout(Model, Width, Layout),
  197    compound_name_arguments(Array, v, Model),
  198    format('{ ', []),
  199    print_table(0, Array, Layout.put(_{ sep:',',
  200                                        end:'\n}',
  201                                        prefix:'  ',
  202                                        options:Options
  203                                      })).
  204
  205print_table(I, Array, Layout) :-
  206    Cols = Layout.cols,
  207    Rows = Layout.rows,
  208    Row is I // Cols,
  209    Col is I mod Cols,
  210    Index is Row + Col * Rows + 1,
  211
  212    % If the next index is outside, we need a newline.  If we are
  213    % also on the last row we have the very last element
  214    (   NIndex is Row + (Col+1) * Rows + 1,
  215        functor(Array, _, LastIndex),
  216        NIndex =< LastIndex
  217    ->  NL = false,
  218        Last = false
  219    ;   NL = true,
  220        (   Row+1 =:= Rows
  221        ->  Last = true
  222        ;   Last = false
  223        )
  224    ),
  225
  226    % If we are not the last on the line and not the last, print the
  227    % cell, padding to the column with and followed by a separator (,)
  228    % Else we print withput padding either a separator or the end.
  229    (   arg(Index, Array, Atom)
  230    ->  (   NL == false,
  231            Last == false
  232        ->  format('~|~@~w~t~*+',
  233                   [print_model_term(Atom, Layout.options),
  234                    Layout.sep, Layout.col_width])
  235        ;   Last == false
  236        ->  format('~@~w', [print_model_term(Atom, Layout.options), Layout.sep])
  237        ;   format('~@~w', [print_model_term(Atom, Layout.options), Layout.end])
  238        ),
  239        Print = true
  240    ;   true
  241    ),
  242
  243    % Emit a newline if this is the last one on the line and we printed this
  244    % cell.
  245    (   Last == true
  246    ->  true
  247    ;   (   Print == true, NL == true
  248        ->  format('~n~w', [Layout.prefix])
  249        ;   true
  250        ),
  251        I2 is I+1,
  252        print_table(I2, Array, Layout)
  253    ).
  254
  255layout(Atoms, Width, _{cols:Cols, rows:Rows, col_width:ColWidth}) :-
  256    length(Atoms, L),
  257    longest(Atoms, Longest),
  258    Cols0 is max(1, Width // (Longest + 3)),
  259    Rows is ceiling(L / Cols0),
  260    Cols is ceiling(L/Rows),
  261    ColWidth is min(Longest+3, Width // Cols).
  262
  263longest(List, Longest) :-
  264    longest(List, 0, Longest).
  265
  266longest([], M, M) :- !.
  267longest([H|T], Sofar, M) :-
  268    write_length(H, Length,
  269                 [ portray(true),
  270                   numbervars(true),
  271                   quoted(true)
  272                 ]),
  273    Length >= Sofar,
  274    !,
  275    longest(T, Length, M).
  276longest([_|T], S, M) :-
  277    longest(T, S, M)