% -----------------------------------------------------------------------------
%  (C) Altran Praxis Limited
% -----------------------------------------------------------------------------
% 
%  The SPARK toolset is free software; you can redistribute it and/or modify it
%  under terms of the GNU General Public License as published by the Free
%  Software Foundation; either version 3, or (at your option) any later
%  version. The SPARK toolset is distributed in the hope that it will be
%  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
%  Public License for more details. You should have received a copy of the GNU
%  General Public License distributed with the SPARK toolset; see file
%  COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
%  the license.
% 
% =============================================================================

%###############################################################################
% PURPOSE
%-------------------------------------------------------------------------------
% Provides support for outputting the simplifier log file.
%###############################################################################





%###############################################################################
% DEPENDENCIES
%###############################################################################

%###############################################################################
% TYPES
%###############################################################################

%###############################################################################
% DATA
%###############################################################################

%###############################################################################
% PREDICATES
%###############################################################################

%===============================================================================
% assert_log_fact(+LogAction, +LogArgument).
%-------------------------------------------------------------------------------
% If a log file has been requested then store the log fact. These facts are
% implicitly associated with the current cerification condition.
%===============================================================================

assert_log_fact(_R, _F) :-
        no_log_file, /* don't assert anything if /nolog has been given */
        !.

assert_log_fact(R, F) :-
        assertz(log_fact(R, F)).

%===============================================================================
% write_log_file_banner.
%-------------------------------------------------------------------------------
% Write out the log file banner.
%===============================================================================

write_log_file_banner :-
        no_log_file,
        !.
write_log_file_banner :-
        typecheck_only(on),
        !.
write_log_file_banner :-
    typecheck_only(off),
    logfile_name(LOGFILE),
    telling(OLDOUT),
    tell(LOGFILE),

    current_output(Stream),
    display_banner(Stream),

    tell(OLDOUT),
    !.

%===============================================================================
% close_log_file.
%-------------------------------------------------------------------------------
% Close the log file.
%===============================================================================

close_log_file :-
        no_log_file,
        !.

close_log_file :-
        typecheck_only(on),
        !.

close_log_file :-
        typecheck_only(off),
        telling(OLDOUT),
        logfile_name(LOGFILE),
        tell(LOGFILE),
        told,
        tell(OLDOUT),
        !.

%===============================================================================
% write_rules_read.
%-------------------------------------------------------------------------------
% Describe the user loaded rules.
%===============================================================================

write_rules_read :-
        /* There is nothing to do if there are no user rule files. */
        \+ log_fact(read_in_user_rule_file, _),
        !.
write_rules_read :-
        \+ no_log_file,
        typecheck_only(off),
        /* There is at least 1 user defined rule file used */
        logfile_name(LOGFILE),
        telling(OLDOUT),
        tell(LOGFILE),
        nl,
        nl,
        prefix(rules_read_sec),
        print('The following user defined rule files have been read:'),
        nl,
        write_the_rule_files,
        write_rule_syntax_errors,
        prefix(semantic_sec),
        print('No semantic checks are performed on the rules.'),
        nl,
        tell(OLDOUT),
        !.

%-------------------------------------------------------------------------------

write_the_rule_files :-
        retract(log_fact(read_in_user_rule_file, Name)),
        prefix(rulefile_read),
        print(Name),
        nl,
        fail.
write_the_rule_files :- !.

%-------------------------------------------------------------------------------

write_rule_syntax_errors :-
        /* There is nothing to do if there are no syntax errors - succeed. */
        \+ log_fact(rule_syntax_error(_, _, _), _),
        !.
write_rule_syntax_errors :-
        /* There is at least 1 syntax error in a rule file - need a header. */
        prefix(syntax_error_sec),
        print('The rule files contain the following syntax errors:'),
        nl,
        write_syntax_errors,
        !.

%-------------------------------------------------------------------------------

write_syntax_errors :-
        retract(log_fact(rule_syntax_error(Complaint, Argument, File), _)),
        maybe_write_filename(File),
        print('        '),
        print(Complaint),
        nl,
        (
                Argument = []
        ;
                Argument \= [],
                print('         Involving: '),
                print(Argument),
                nl
        ),
        fail.

write_syntax_errors :- !.

%-------------------------------------------------------------------------------

maybe_write_filename(Name) :-
        \+ syntax_error_in_file(Name),
        !,

        convert_file_for_display(Name, DisplayFile),
        prefix(syntax_err_rep),
        print(DisplayFile),
        nl,
        assertz(syntax_error_in_file(Name)).

maybe_write_filename(_) :- !.

%===============================================================================
% write_rules_read.
%-------------------------------------------------------------------------------
% Describe the facts recorded in processing a path function or verification
% condition.
%===============================================================================

write_log_facts :-
        no_log_file,
        retractall(log_fact(_, _)),
        !.

write_log_facts :-
        typecheck_only(on),
        retractall(log_fact(_, _)),
        !.

write_log_facts :-
        typecheck_only(off),
        logfile_name(LOGFILE),
        telling(OLDOUT),
        tell(LOGFILE),
        nl,
        nl,
        write_vc_or_pf_header,
        process_log_facts,
        tell(OLDOUT),
        !.

%-------------------------------------------------------------------------------

write_overall_rule_summary :-
        overall_rule_summary(_, _),
        !,
        /* At least 1 user rule has been used in the proof of this subprogram */
        \+ no_log_file,
        typecheck_only(off),
        /* There is at least 1 user defined rule file used */
        logfile_name(LOGFILE),
        telling(OLDOUT),
        tell(LOGFILE),
        nl,
        nl,
        prefix(overall_summary),
        print('Overall summary of VCs using user rules.'),
        nl,
        write_the_overall_summary,
        tell(OLDOUT).

write_overall_rule_summary :- !.

%-------------------------------------------------------------------------------

write_the_overall_summary :-
        overall_rule_summary(File:_, _),
        !,
        convert_file_to_base_name(File, DisplayFile),

        prefix(rulefile),
        print(DisplayFile),
        nl,
        overall_summary_of_file(File),
        write_the_overall_summary.

write_the_overall_summary :- !.

%-------------------------------------------------------------------------------

overall_summary_of_file(File) :-
        overall_rule_summary(File:Rule, _),
        !,
        prefix(rule),
        print(Rule),
        nl,
        overall_summary_of_rule(File:Rule),
        overall_summary_of_file(File).

overall_summary_of_file(_) :- !.

%-------------------------------------------------------------------------------

overall_summary_of_rule(RuleId) :-
        retract(overall_rule_summary(RuleId, VCn)),
        !,
        /* At least one VC has been proved using this rule */
        prefix(vcs),
        print(VCn),
        overall_summary_of_rule_rep(RuleId),
        nl.

overall_summary_of_rule(_) :- !.

%-------------------------------------------------------------------------------

overall_summary_of_rule_rep(File:Rule) :-
        retract(overall_rule_summary(File:Rule, VCn)),
        print(', '),
        print(VCn),
        fail.

overall_summary_of_rule_rep(_) :- !.

%-------------------------------------------------------------------------------

write_vc_or_pf_header :-
        path_functions,
        write_path_functions_header,
        !.

write_vc_or_pf_header :-
        print('@@@@@@@@@@  VC: '),
        vc_name(X),
        print(X),
        print('  @@@@@@@@@@'),
        nl,
        !.

%-------------------------------------------------------------------------------



/*** write_path_functions_header ***/
write_path_functions_header :-
        retract(stmt_line(L)),
        print(L),
        nl,
        fail.

write_path_functions_header :-
        retract(succ_line(L)),
        print(L),
        nl,
        fail.

write_path_functions_header :-
        retract(path_line(L)),
        print(L),
        nl,
        fail.

write_path_functions_header :- !.



%-------------------------------------------------------------------------------

process_log_facts :-
        \+ log_fact(_, _),
        !,
        state_no_simplification_performed.
process_log_facts :-
        retract(log_fact(ACTION, ARGUMENTS)),
        write_log_entry(ACTION, ARGUMENTS),
        nl,
        fail.
process_log_facts :-
        !,
        summarise_user_rule_use.

%-------------------------------------------------------------------------------

state_no_simplification_performed :-
        print('     NO SIMPLIFICATION ACTIONS PERFORMED.'),
        nl,
        !.

%-------------------------------------------------------------------------------

write_log_entry(ACTION, ARGUMENTS) :-
        path_functions,
        !,
        write_pf_entry(ACTION, ARGUMENTS).
write_log_entry(ACTION, ARGUMENTS) :-
        write_vc_entry(ACTION, ARGUMENTS).

%-------------------------------------------------------------------------------

summarise_user_rule_use :-
        rule_summary(_, _),
        !,
        nl,
        prefix(vc_number),
        current_vc_number(N),
        print(N),
        print(': Summary of user rule application.'),
        nl,
        summarise_user_rule_use_rep.

summarise_user_rule_use :- !.

%-------------------------------------------------------------------------------

summarise_user_rule_use_rep :-
        rule_summary(File:_, _),
        !,
        convert_file_to_base_name(File, DisplayFile),

        prefix(rulefile),
        print(DisplayFile),
        nl,
        summary_of_file(File),
        summarise_user_rule_use_rep.

summarise_user_rule_use_rep :- !.

%-------------------------------------------------------------------------------

summary_of_file(File) :-
        rule_summary(File:Rule, _),
        !,
        prefix(rule),
        print(Rule),
        nl,
        summary_of_rule(File:Rule),
        summary_of_file(File).

summary_of_file(_) :- !.

%-------------------------------------------------------------------------------

summary_of_rule(RuleId) :-
        summary_of_conclusions(RuleId),
        summary_of_hypotheses(RuleId),
        add_to_overall_summary(RuleId),
        !.

%-------------------------------------------------------------------------------

add_to_overall_summary(RuleId) :-
        current_vc_number(VCn),
        \+ overall_rule_summary(RuleId, VCn),
        !,
        assertz(overall_rule_summary(RuleId, VCn)).

add_to_overall_summary(_) :- !.

%-------------------------------------------------------------------------------

summary_of_conclusions(RuleId) :-
        retract(rule_summary(RuleId, conc(N))),
        !,
        /* At least one conclusion has been proved using this rule */
        prefix(conclusion),
        print(N),
        summary_of_conclusions_rep(RuleId),
        nl.

summary_of_conclusions(_) :- !.

%-------------------------------------------------------------------------------

summary_of_conclusions_rep(File:Rule) :-
        retract(rule_summary(File:Rule, conc(N))),
        print(', '),
        print(N),
        fail.

summary_of_conclusions_rep(_) :- !.

%-------------------------------------------------------------------------------

summary_of_hypotheses(RuleId) :-
        retract(rule_summary(RuleId, hyp(N))),
        !,
        /* At least one hypothesis has been proved using this rule */
        prefix(hypotheses),
        print(N),
        summary_of_hypotheses_rep(RuleId),
        nl.

summary_of_hypotheses(_) :- !.

%-------------------------------------------------------------------------------

summary_of_hypotheses_rep(File:Rule) :-
        retract(rule_summary(File:Rule, hyp(N))),
        print(', '),
        print(N),
        fail.

summary_of_hypotheses_rep(_) :- !.

%===============================================================================
% write_vc_entry(+ACTION, +ARGUMENTS).
%-------------------------------------------------------------------------------
% Writes an entry for facts logged in proving verification conditions.
%===============================================================================

/*  1 */  write_vc_entry(hyp_split, [N, [Na, A], [Nb, B], D]) :-
                get_indentation(D, Indent),
                prefix(restructuring),
                print('Hypothesis H'),
                print(N),
                print(' has now been split into two, giving:'),
                nl,
                print(Indent),
                indent5, prefix(restructuring),
                print('H'),
                print(Na),
                print(':  '),
                print(A),
                nl,
                print(Indent),
                indent5, prefix(restructuring),
                print('H'),
                print(Nb),
                print(':  '),
                print(B),
                !.

/*  2 */  write_vc_entry(forwardchain, [Nab, Na, Nb, B, D]) :-
                get_indentation(D, Indent),
                prefix(addition),
                print('Using "A->B, A |- B" on hypotheses H'),
                print(Nab),
                print(' & H'),
                print(Na),
                print(' yields a new hypothesis:'),
                nl,
                print(Indent),
                indent5, prefix(addition),
                print('H'),
                print(Nb),
                print(':  '),
                print(B),
                !.

/*  3 */  write_vc_entry(backchain, [Nab, Nb, Na, A, D]) :-
                get_indentation(D, Indent),
                prefix(addition),
                print('Using "A->B, not B |- not A" on hypotheses H'),
                print(Nab),
                print(' & H'),
                print(Nb),
                print(' yields a new hypothesis:'),
                nl,
                print(Indent),
                indent5, prefix(addition),
                print('H'),
                print(Na),
                print(':  '),
                print(A),
                !.

/*  4 */  write_vc_entry(restructured, [N, F, D]) :-
                get_indentation(D, Indent),
                prefix(restructuring),
                print('Restructured hypothesis H'),
                print(N),
                print(' into:'),
                nl,
                print(Indent),
                indent5, prefix(restructuring),
                print('H'),
                print(N),
                print(':  '),
                print(F),
                !.

/*  5 */  write_vc_entry(simplified, [HorC, N, _OLD, NEW]) :-
                (
                   HorC = hyp,  HC = 'H'
                ;
                   HorC = conc, HC = 'C'
                ),
                prefix(simplification),
                print('Simplified '),
                print(HC),
                print(N),
                print(' on reading formula in, to give:'),
                nl,
                indent5, prefix(simplification),
                print(HC),
                print(N),
                print(':  '),
                print(NEW),
                !.

/* 5a */  write_vc_entry(simplified_conc, [N, _OLD, NEW, D]) :-
                get_indentation(D, Indent),
                prefix(simplification),
                print('Simplified C'),
                print(N),
                print(' further, to give:'),
                nl,
                print(Indent),
                indent5, prefix(simplification),
                print('C'),
                print(N),
                print(':  '),
                print(NEW),
                !.

/*  6 */  write_vc_entry(conc_split, [N, [Na, A], [Nb, B], D]) :-
                get_indentation(D, Indent),
                prefix(restructuring),
                print('Conclusion C'),
                print(N),
                print(' has now been split into two, giving:'),
                nl,
                print(Indent),
                indent5, prefix(restructuring),
                print('C'),
                print(Na),
                print(':  '),
                print(A),
                nl,
                print(Indent),
                indent5, prefix(restructuring),
                print('C'),
                print(Nb),
                print(':  '),
                print(B),
                !.

/*  7 */  write_vc_entry(duplicate_hyp, [N, F]) :-
                prefix(elimination),
                print('Attempted addition of new hypothesis:'),
                nl,
                indent5, indent5,
                print(F),
                nl,
                indent5,
                print('eliminated: this already exists (as H'),
                print(N),
                print(').'),
                !.

/* 7a */  write_vc_entry(repeat_hyp, [N, M]) :-
                prefix(elimination),
                print('Hypothesis H'),
                print(N),
                print(' has been replaced by "true".  (It is already present, as H'),
                print(M),
                print(').'),
                !.

/*  8 */  write_vc_entry(combined_hyps, [Na, Nb, N, Formula]) :-        /* SEPR 1077     */
                prefix(simplification),                                 /* (generalised) */
                print('Hypotheses H'),
                print(Na),
                print(' & H'),
                print(Nb),
                print(' together imply that'),
                nl,
                indent5, indent5,
                print(Formula),
                print('.'),
                nl,
                indent5,
                print('H'),
                print(Na),
                print(' & H'),
                print(Nb),
                print(' have therefore been deleted and a new H'),
                print(N),
                print(' added to this effect.'),
                !.

/*  9 */  write_vc_entry(proved, [N, C, Hs, CC]) :-
                prefix(proof),
                print('Proved C'),
                print(N),
                print(':  '),
                print(CC),
                (
                   CC = C
                ;
                   nl,
                   indent5,
                   print('via its standard form, which is:'),
                   nl,
                   indent5,
                   print('Std.Fm C'),
                   print(N),
                   print(':  '),
                   print(C)
                ),
                !,
                (
                   Hs=[]
                ;
                   nl,
                   indent5,
                   (
                      Hs=[H],
                      print('using hypothesis H'),
                      print(H),
                      print('.')
                   ;
                      print('using hypotheses H'),
                      write_hyp_numbers_list(Hs, 'H'),
                      print('.')
                   )
                ),
                !.

/* 9a */  write_vc_entry(proved_subgoal, [N, C, Hs, CC, D]) :-
                get_indentation(D, Indent),
                prefix(proof),
                print('Proved subgoal C'),
                print(N),
                (
                   CC = C
                ;
                   print(' via its simplified form, which is:'),
                   nl,
                   print(Indent),
                   indent5,
                   print('Std.Fm C'),
                   print(N),
                   print(':  '),
                   print(C)
                ),
                !,
                (
                   Hs=[]
                ;
                   nl,
                   print(Indent),
                   indent5,
                   (
                      Hs=[H],
                      print('using hypothesis H'),
                      print(H),
                      print('.')
                   ;
                      print('using hypotheses H'),
                      write_hyp_numbers_list(Hs, 'H'),
                      print('.')
                   )
                ),
                !.

/* 9b */  write_vc_entry(proved_by_framing, [N, C, Method]) :-
                prefix(proof),
                print('Proved C'),
                print(N),
                print(':  '),
                print(C),
                nl,
                indent5,
                print('by '),
                print(Method),
                print('.'),
                !.

/* 9c */  write_vc_entry(proved_by_framing_hyp, [ConcNumber, HypNumber, ConcExp, Method]) :-
                prefix(proof),
                print('Proved C'),
                print(ConcNumber),
                print(':  '),
                print(ConcExp),
                nl,
                indent5,
                print('by '),
                print(Method),
                print(' using hypothesis H'),
                print(HypNumber),
                print('.'),
                !.

/* 10 */  write_vc_entry(contradiction, [K, Hs]) :-
                prefix(contradiction),
                print('Established a contradiction ['),
                print(K),
                (
                   Hs=[],
                   print('].')
                ;
                   Hs=[H],
                   print('] using hypothesis H'),
                   print(H),
                   print('.')
                ;
                   print('] among the following hypotheses:'),
                   nl,
                   indent5, indent5,
                   print('H'),
                   write_hyp_numbers_list(Hs, 'H'),
                   print('.')
                ),
                !.

/* 11 */  write_vc_entry(forwardchain2, [N, Hs, B]) :-
                prefix(restructuring),
                print('Using "A->B, A |- B" on H'),
                print(N),
                (
                   Hs=[],
                   print(', given that "A" is obvious, we simplify this to:')
                ;
                   (
                      Hs=[H],
                      print(', given H'),
                      print(H)
                   ;
                      print(', given H'),
                      write_hyp_numbers_list(Hs, 'H')
                   ),
                   print(', we simplify the former to:')
                ),
                nl,
                indent5, prefix(restructuring),
                print('H'),
                print(N),
                print(':  '),
                print(B),
                !.

/* 12 */  write_vc_entry(eliminated_hyp, [N, Message, Hs]) :-
                prefix(elimination),
                print('Eliminated hypothesis H'),
                print(N),
                print(' ('),
                print(Message),
                (
                   Hs=[]
                ;
                   print(', given H'),
                   (
                      Hs=[H],
                      print(H)
                   ;
                      write_hyp_numbers_list(Hs, 'H')
                   )
                ),
                print(').'),
                !.

/* 13 */  write_vc_entry(substituted, [D, N, V, E]) :-
                integer(N),
                get_indentation(D, Indent),
                prefix(substitution),
                print('Eliminated hypothesis H'),
                print(N),
                print('.'),
                nl,
                print(Indent),
                indent5,
                print('This was achieved by replacing all occurrences of '),
                print(V),
                print(' by:'),
                nl,
                print(Indent),
                indent5, indent5,
                print(E),
                print('.'),
                !.

/* 13a */ write_vc_entry(substituted, [D, N, V, E]) :-
                \+ integer(N),
                get_indentation(D, Indent),
                prefix(substitution),
                print('Applied substitution rule '),
                print(N),
                print('.'),
                nl,
                print(Indent),
                indent5,
                print('This was achieved by replacing all occurrences of '),
                print(V),
                print(' by:'),
                nl,
                print(Indent),
                indent5, indent5,
                print(E),
                print('.'),
                !.

/* 13b */  write_vc_entry(substituted_fld, [D, N, V, E]) :-
                integer(N),
                get_indentation(D, Indent),
                prefix(substitution),
                print('Substituted hypothesis H'),
                print(N),
                print('.'),
                nl,
                print(Indent),
                indent5,
                print('This was achieved by replacing all occurrences of '),
                print(V),
                print(' by:'),
                nl,
                print(Indent),
                indent5, indent5,
                print(E),
                print('.'),
                !.

/* 13c */ write_vc_entry(substituted_fld, [D, N, V, E]) :-
                \+ integer(N),
                get_indentation(D, Indent),
                prefix(substitution),
                print('Applied substitution rule '),
                print(N),
                print('.'),
                nl,
                print(Indent),
                indent5,
                print('This was achieved by replacing all occurrences of '),
                print(V),
                print(' by:'),
                nl,
                print(Indent),
                indent5, indent5,
                print(E),
                print('.'),
                !.

/* 14 */  write_vc_entry(proved_all, []) :-
                prefix(proof),
                print('PROVED VC.'),
                !.

/* 15 */  write_vc_entry(subst_hyp, [D, N, F]) :-
                get_indentation(D, _Indent),
                prefix(substituted),
                print('New H'),
                print(N),
                print(':  '),
                print(F),
                !.

/* 16 */  write_vc_entry(subst_conc, [D, N, F]) :-
                get_indentation(D, _Indent),
                prefix(substituted),
                print('New C'),
                print(N),
                print(':  '),
                print(F),
                !.

/* 17 */  write_vc_entry(further_simplified, [HorC, N, _OLD, NEW | HYPS]) :-
                (
                   HorC = hyp,  HC = 'H'
                ;
                   HorC = conc, HC = 'C'
                ),
                prefix(simplification),
                print('Simplified '),
                print(HC),
                print(N),
                print(' further'),
                (
                   HYPS = [Hypotheses],
                   Hypotheses \= [],
                   print(' (given H'),
                   (
                      Hypotheses = [SingleHyp],
                      print(SingleHyp)
                   ;
                      write_hyp_numbers_list(Hypotheses, 'H')
                   ),
                   print(')')
                ;
                   true
                ),
                print(', to give:'),
                nl,
                indent5, prefix(simplification),
                print(HC),
                print(N),
                print(':  '),
                print(NEW),
                !.

/* 18 */  write_vc_entry(subst_elim_hyp, [D, N, VAR]) :-
                integer(N),     /* fail in other case */
                get_indentation(D, Indent),
                prefix(elimination),
                print('Eliminated hypothesis H'),
                print(N),
                print(', which only specifies a value for '),
                print(VAR),
                print('.'),
                nl,
                print(Indent),
                indent5,
                print('This is not referred to anywhere else in the VC.'),
                !.

/* 18a */  write_vc_entry(subst_fld, [D, N, VAR]) :-
                integer(N),     /* fail in other case */
                get_indentation(D, _Indent),
                prefix(elimination),
                print('Substituted hypothesis H'),
                print(N),
                print(', which specifies an equivalence for '),
                print(VAR),
                print('.'),
                !.

/* 19 */  write_vc_entry(eliminated_conc, [N, M]) :-
                prefix(elimination),
                print('Eliminated conclusion C'),
                print(N),
                print(', which is a duplicate of C'),
                print(M),
                print('.'),
                !.

/* 20 */  write_vc_entry(unwrapping, [N, D]) :-
                get_indentation(D, _Indent),
                prefix(restructuring),
                print('Attempting to prove quantified formula C'),
                print(N),
                print(' by "unwrapping" it.'),
                !.

/* 21 */  write_vc_entry(implies_conc, [N, _P, _Q, D]) :-
                get_indentation(D, Indent),
                prefix(restructuring),
                print('Conclusion C'),
                print(N),
                print(' is an implication formula [P->Q].'),
                nl,
                print(Indent),
                indent5,
                print('Attempting to prove this by proving Q while adding P to the hypotheses.'),
                !.

/* 22 */  write_vc_entry(by_cases, [N, [Case1, Case2], D]) :-
                get_indentation(D, Indent),
                prefix(restructuring),
                print('Attempting to prove C'),
                print(N),
                print(' by cases, depending on whether'),
                nl,
                write_out_cases(Indent, [Case1, Case2]),
                print(Indent),
                indent5,
                print('given the need to simplify update(A, [I], X) accesses in C'),
                print(N),
                print('.'),
                !.

/* 22a */  write_vc_entry(by_cases_hyp, [N, CaseList, D]) :-
                get_indentation(D, Indent),
                prefix(restructuring),
                print('Attempting to prove C'),
                print(N),
                print(' by showing that each of the following cases'),
                nl,
                write_out_cases(Indent, CaseList),
                print(Indent),
                indent5,
                print('are provable.'),
                !.

/* 23 */  write_vc_entry(add_imp_hyps, [D]) :-  /* Ignore hypothesis list */
                get_indentation(D, _Indent),
                prefix(addition),
                print('Added new hypotheses (in proving an implication formula).'),
                !.

/* 24 */  write_vc_entry(new_hyp, [N, H, D]) :-
                get_indentation(D, _Indent),
                indent5,
                prefix(addition),
                print('New H'),
                print(N),
                print(':  '),
                print(H),
                !.

/* 25 */  write_vc_entry(new_hyp_for_case, [N, H, C, D]) :-
                get_indentation(D, _Indent),
                prefix(addition),
                print('Case '),
                print(C),
                print(' - New H'),
                print(N),
                print(':  '),
                print(H),
                !.

/* 26 */  write_vc_entry(new_goal, [N, C, D]) :-
                get_indentation(D, _Indent),
                prefix(addition),
                print('New subgoal C'),
                print(N),
                print(':  '),
                print(C),
                !.

/* 27a */  write_vc_entry(rule_proved_conc, [N, C, File:Rule,
                          rewrite(NewC, Conditions), RuleSort]) :-
                prefix(proof),
                print('Proved C'),
                print(N),
                print(':  '),
                print(C),
                nl,
                indent5,
                print('This was achieved by applying the rewrite rule '),
                print(Rule),
                nl,
                indent5,
                maybe_write_rulefile(File:Rule, RuleSort, conc(N)),
                print('to rewrite this conclusion to:'),
                nl,
                prefix(substituted),
                print('C'),
                print(N),
                print(':  '),
                print(NewC),
                write_conditions_list(Conditions),
                !.

/* 27b */  write_vc_entry(rule_proved_conc, [N, C, File:Rule, inference([]), RuleSort]) :-
                prefix(proof),
                print('Proved C'),
                print(N),
                print(':  '),
                print(C),
                nl,
                indent5,
                print('This was achieved by applying the inference rule '),
                print(Rule),
                nl,
                indent5,
                maybe_write_rulefile(File:Rule, RuleSort, conc(N)),
                print('to infer this conclusion directly (rule has no side-conditions).'),
                !.

/* 27c */  write_vc_entry(rule_proved_conc, [N, C, File:Rule, inference(Conditions), RuleSort]) :-
                prefix(proof),
                print('Proved C'),
                print(N),
                print(':  '),
                print(C),
                nl,
                indent5,
                print('This was achieved by applying the inference rule '),
                print(Rule),
                nl,
                indent5,
                maybe_write_rulefile(File:Rule, RuleSort, conc(N)),
                print('to infer this conclusion from its side-conditions,'),
                nl,
                indent5,
                print('which were established as follows:'),
                write_conditions_list_items(Conditions),
                !.

/* 28  */  write_vc_entry(applied_rule, [N, H, File:Rule, rewrite(OldH, Conditions), RuleSort]) :-
                prefix(addition),
                print('New H'),
                print(N),
                print(':  '),
                print(H),
                nl,
                indent5,
                print('This was achieved by applying the rewrite rule '),
                print(Rule),
                nl,
                indent5,
                maybe_write_rulefile(File:Rule, RuleSort, hyp(N)),
                print('to rewrite existing hypothesis H'),
                (
                    get_hyp(OldH, _, M)
                ;
                   M = '?'      /* catch-all case: should never be used */
                ),
                print(M),
                print(' to give the above formula.'),
                write_conditions_list(Conditions),
                !.

/* 28b */  write_vc_entry(applied_rule, [N, H, File:Rule, inference([]), RuleSort]) :-
                prefix(addition),
                print('New H'),
                print(N),
                print(':  '),
                print(H),
                nl,
                indent5,
                print('This was achieved by applying the inference rule '),
                print(Rule),
                nl,
                indent5,
                maybe_write_rulefile(File:Rule, RuleSort, hyp(N)),
                print('to infer this hypothesis directly (rule has no side-conditions).'),
                !.

/* 28c */  write_vc_entry(applied_rule, [N, H, File:Rule, inference(Conditions), RuleSort]) :-
                prefix(addition),
                print('New H'),
                print(N),
                print(':  '),
                print(H),
                nl,
                indent5,
                print('This was achieved by applying the inference rule '),
                print(Rule),
                nl,
                indent5,
                maybe_write_rulefile(File:Rule, RuleSort, hyp(N)),
                print('to infer this hypothesis from its side-conditions,'),
                nl,
                indent5,
                print('which were established as follows:'),
                write_conditions_list_items(Conditions),
                !.

/* 30 */  write_vc_entry(composite_rewrite, [ConcNumber, Conc, HypNumberList]) :-
                prefix(restructuring),
                print('Conclusion C'),
                print(ConcNumber),
                print(':  '),
                print(Conc),
                nl,
                indent5,
                print('is transformed by replacing variables with update structures via:'),
                nl,
                indent5, indent5,
                print('H'),
                write_hyp_numbers_list(HypNumberList, 'H'),
                print('.'),
                !.

/* 31 */ write_vc_entry(zombiescope_exceed_limit, [_VCNumber]) :-
                prefix(hyp_limit),
                nl,
                print('Number of hyps in DPC exceeds limit specified by -hyp-limit.'),
                nl,
                print('Skipping all hypotheses in DPC.'),
                nl,
                print('No dead path detection performed for this DPC.'),
                nl,
                !.

/* ?? */  write_vc_entry(UNEXPECTED, ARGS) :-
                print('???  '),
                print(UNEXPECTED),
                nl,
                indent5, indent5,
                print(ARGS),
                !.

%-------------------------------------------------------------------------------

write_out_cases(Indent, CaseList):-
    write_out_cases_x(Indent, 1, CaseList),
    !.

write_out_cases_x(Indent, CaseNumber, [Case]):-
    print(Indent),
    indent5,
    print('('),
    print(CaseNumber),
    print(')  '),
    print(Case),
    print(','),
    nl,
    !.

write_out_cases_x(Indent, CaseNumber, [Case | CaseList]):-
    NextCaseNumber is CaseNumber+1,
    print(Indent),
    indent5,
    print('('),
    print(CaseNumber),
    print(')  '),
    print(Case),
    print(', or'),
    nl,
    write_out_cases_x(Indent, NextCaseNumber, CaseList).

%-------------------------------------------------------------------------------

maybe_write_rulefile(File:Rule, user_inference_rule, Action) :-
        !,
        convert_file_to_base_name(File, DisplayFile),
        print('[from rulefile '),
        print(DisplayFile),
        print('] '),
        add_to_rule_summary(File:Rule, Action).
maybe_write_rulefile(File:Rule, user_rewrite_rule, Action) :-
        !,
        convert_file_to_base_name(File, DisplayFile),
        print('[from rulefile '),
        print(DisplayFile),
        print('] '),
        add_to_rule_summary(File:Rule, Action).
maybe_write_rulefile(_, _, _) :- !.

%-------------------------------------------------------------------------------

write_conditions_list([]) :-
        nl,
        indent5,
        print('This rule has an empty list of side-conditions.'),
        !.
write_conditions_list([One]) :-
        nl,
        indent5,
        print('This rule could be applied because its side-condition holds, as follows:'),
        write_conditions_list_items([One]),
        !.
write_conditions_list(List) :-
        nl,
        indent5,
        print('This rule could be applied because its side-conditions hold, as follows:'),
        write_conditions_list_items(List),
        !.

%-------------------------------------------------------------------------------

write_conditions_list_items([]) :-
        !.

write_conditions_list_items([proved(goal(Condition), [], []) | Rest]) :-
        nl,
        indent5,
        prefix(sidecondition),
        print('Immediate condition '),
        print(Condition),
        write(' evaluated successfully'),
        !,
        write_conditions_list_items(Rest).

write_conditions_list_items([proved(Condition, [], []) | Rest]) :-
        nl,
        indent5,
        prefix(sidecondition),
        print('By simple reasoning, proved: '),
        print(Condition),
        !,
        write_conditions_list_items(Rest).

write_conditions_list_items([proved(Condition, Hyps, []) | Rest]) :-
        nl,
        indent5,
        prefix(sidecondition),
        print('From H'),
        write_hyp_numbers_list(Hyps, 'H'),
        print(', proved: '),
        print(Condition),
        !,
        write_conditions_list_items(Rest).

%-------------------------------------------------------------------------------

add_to_rule_summary(RuleId, Use) :-
        \+ rule_summary(RuleId, Use),
        !,
        assertz(rule_summary(RuleId, Use)).
add_to_rule_summary(_, _) :- !.

%===============================================================================
% write_pf_entry(+ACTION, +ARGUMENTS).
%-------------------------------------------------------------------------------
% Writes an entry for facts logged in proving path functions.
%===============================================================================

/*  1 */  write_pf_entry(hyp_split, [N, [Na, A], [Nb, B]|_]) :-
                prefix(restructuring),
                print('Traversal condition TC#'),
                print(N),
                print(' has now been split into two, giving:'),
                nl,
                indent5, prefix(restructuring),
                print('TC#'),
                print(Na),
                print(':  '),
                print(A),
                nl,
                indent5, prefix(restructuring),
                print('TC#'),
                print(Nb),
                print(':  '),
                print(B),
                !.

/*  2 */  write_pf_entry(forwardchain, [Nab, Na, Nb, B|_]) :-
                prefix(addition),
                print('Using "A->B, A |- B" on traversal condition TC#'),
                print(Nab),
                print(' & TC#'),
                print(Na),
                print(' yields a new traversal condition:'),
                nl,
                indent5, prefix(addition),
                print('TC#'),
                print(Nb),
                print(':  '),
                print(B),
                !.

/*  3 */  write_pf_entry(backchain, [Nab, Nb, Na, A|_]) :-
                prefix(addition),
                print('Using "A->B, not B |- not A" on traversal condition TC#'),
                print(Nab),
                print(' & TC#'),
                print(Nb),
                print(' yields a new traversal condition:'),
                nl,
                indent5, prefix(addition),
                print('TC#'),
                print(Na),
                print(':  '),
                print(A),
                !.

/*  4 */  write_pf_entry(restructured, [N, F|_]) :-
                prefix(restructuring),
                print('Restructured traversal condition TC#'),
                print(N),
                print(' into:'),
                nl,
                indent5, prefix(restructuring),
                print('TC#'),
                print(N),
                print(':  '),
                print(F),
                !.

/* 5a */  write_pf_entry(simplified, [hyp, N, _OLD, NEW]) :-
                prefix(simplification),
                print('Simplified TC#'),
                print(N),
                print(' on reading in, to give:'),
                nl,
                indent5, prefix(simplification),
                print('TC#'),
                print(N),
                print(':  '),
                print(NEW),
                !.

/* 5b */  write_pf_entry(simplified, [conc, _N, _OLD, NEW]) :-
                prefix(simplification),
                print('Simplified path action part on reading in, to give:'),
                nl,
                write_new_action_part(NEW),
                !.

/*  6 */  /* conc_split should not occur with path functions! */

/*  7 */  write_pf_entry(duplicate_hyp, [N, F]) :-
                prefix(elimination),
                print('Attempted addition of new traversal condition:'),
                nl,
                indent5, indent5,
                print(F),
                nl,
                indent5,
                print('eliminated: this already exists (as TC#'),
                print(N),
                print(').'),
                !.

/*  8 */  write_pf_entry(combined_hyps, [Na, Nb, N, A=B]) :-
                prefix(simplification),
                print('Traversal conditions TC#'),
                print(Na),
                print(' & TC#'),
                print(Nb),
                print(' together imply that'),
                nl,
                indent5, indent5,
                print(A=B),
                print('.'),
                nl,
                indent5,
                print('TC#'),
                print(Na),
                print(' & TC#'),
                print(Nb),
                print(' have therefore been deleted and a new TC#'),
                print(N),
                print(' added to this effect.'),
                !.

/*  9 */  /* proved should not occur with path functions! */

/* 10 */  write_pf_entry(contradiction, [K, Hs]) :-
                prefix(contradiction),
                print('Established a contradiction ['),
                print(K),
                (
                   Hs=[],
                   print('].')
                ;
                   Hs=[H],
                   print('] using traversal condition TC#'),
                   print(H),
                   print('.')
                ;
                   print('] among the following traversal conditions:'),
                   nl,
                   indent5, indent5,
                   print('TC#'),
                   write_hyp_numbers_list(Hs, 'TC#'),
                   print('.')
                ),
                !.

/* 11 */  write_pf_entry(forwardchain2, [N, Hs, B]) :-
                prefix(restructuring),
                print('Using "A->B, A |- B" on TC#'),
                print(N),
                (
                   Hs=[],
                   print(', given that "A" is obvious, we simplify this to:')
                ;
                   print(', given TC#'),
                   (
                      Hs=[H],
                      print(H)
                   ;
                      write_hyp_numbers_list(Hs, 'TC#')
                   ),
                   print(', we simplify the former to:')
                ),
                nl,
                indent5, prefix(restructuring),
                print('TC#'),
                print(N),
                print(':  '),
                print(B),
                !.

/* 12 */  write_pf_entry(eliminated_hyp, [N, Message, Hs]) :-
                prefix(elimination),
                print('Eliminated traversal condition TC#'),
                print(N),
                print(' ('),
                print(Message),
                (
                   Hs=[]
                ;
                   print(', given TC#'),
                   (
                      Hs=[H],
                      print(H)
                   ;
                      write_hyp_numbers_list(Hs, 'TC#')
                   )
                ),
                print(').'),
                !.

/* 13 */  write_pf_entry(substituted, [_D, N, V, E]) :-         /* ignore depth D */
                prefix(substitution),
                print('Used traversal condition TC#'),
                print(N),
                print(' to replace all occurrences of '),
                print(V),
                print(' by:'),
                nl,
                indent5, indent5,
                print(E),
                print('.'),
                !.

/* 14 */  write_pf_entry(proved_all, []) :-
                prefix(proof),
                print('PATH ELIMINATED.'),
                !.

/* 15 */  write_pf_entry(subst_hyp, [_D, N, F]) :-              /* ignore depth D */
                prefix(substituted),
                print('New TC#'),
                print(N),
                print(':  '),
                print(F),
                !.

/* 16 */  write_pf_entry(subst_conc, [_D, 1, F]) :-             /* ignore depth D */
                prefix(substituted),
                print('New action part is:'),
                nl,
                write_new_action_part(F),
                !.

/* 17a*/  write_pf_entry(further_simplified, [hyp, N, _OLD, NEW | HYPS]) :-
                prefix(simplification),
                print('Simplified TC#'),
                print(N),
                print(' further'),
                (
                   HYPS= [Hypotheses],
                   Hypotheses \= [],
                   print(' (given TC#'),
                   (
                      Hypotheses = [SingleHyp],
                      print(SingleHyp)
                   ;
                      write_hyp_numbers_list(Hypotheses, 'TC#')
                   ),
                   print(')')
                ;
                   true
                ),
                print(', to give:'),
                nl,
                indent5, prefix(simplification),
                print('TC#'),
                print(N),
                print(':  '),
                print(NEW),
                !.

/* 17b*/  write_pf_entry(further_simplified, [conc, _N, _OLD, NEW | HYPS]) :-
                prefix(simplification),
                print('Simplified path action part'),
                (
                   HYPS = [Hypotheses],
                   Hypotheses \= [],
                   print(' (given TC#'),
                   (
                      Hypotheses = [SingleHyp],
                      print(SingleHyp)
                   ;
                      write_hyp_numbers_list(Hypotheses, 'TC#')
                   ),
                   print(')')
                ;
                   true
                ),
                print(' to give:'),
                nl,
                write_new_action_part(NEW),
                !.

/* ?? */  write_pf_entry(UNEXPECTED, ARGS) :-
                print('???  '),
                print(UNEXPECTED),
                nl,
                indent5, indent5,
                print(ARGS),
                !.

%-------------------------------------------------------------------------------

write_hyp_numbers_list([H1,H2], PREFIX) :-
        print(H1),
        print(' & '),
        print(PREFIX),
        print(H2),
        !.

write_hyp_numbers_list([H1], _PREFIX) :-
        print(H1),
        !.

write_hyp_numbers_list([H1|Hs], PREFIX) :-
        print(H1),
        print(', '),
        print(PREFIX),
        !,
        write_hyp_numbers_list(Hs, PREFIX),
        !.

%-------------------------------------------------------------------------------

write_new_action_part(X & Y) :-
        write_new_action_part(X),
        print(' &'),
        nl,
        write_new_action_part(Y),
        !.
write_new_action_part(X := Y) :-
        indent5, indent5,
        print(X),
        print('\' := '),
        print(Y),
        !.

%===============================================================================
% write_vc_entry(+ACTION).
%-------------------------------------------------------------------------------
% Write out an appropiate identifier for the action class.
%===============================================================================

prefix( proof          ) :- print('***  '), !.
prefix( elimination    ) :- print('---  '), !.
prefix( restructuring  ) :- print('>>>  '), !.
prefix( simplification ) :- print('%%%  '), !.
prefix( addition       ) :- print('+++  '), !.
prefix( contradiction  ) :- print('###  '), !.
prefix( substitution   ) :- print('-S-  '), !.
prefix( substituted    ) :- print('<S>  '), !.
prefix( sidecondition  ) :- print('<<<  '), !.
prefix( rules_read_sec ) :- print('RRS  '), !.
prefix( rulefile_read  ) :- print('&&&  '), !.
prefix(syntax_error_sec) :- print('STX  '), !.
prefix( syntax_err_rep ) :- print('!!!  '), !.
prefix( semantic_sec   ) :- print('SEM  '), !.
prefix( vc_number      ) :- print('VCN  '), !.
prefix( rulefile       ) :- print('FIL  '), !.
prefix( rule           ) :- print('RUL     '), !.
prefix( conclusion     ) :- print('CON        '), !.
prefix( hypotheses     ) :- print('HYP        '), !.
prefix( overall_summary) :- print('OVR  '), !.
prefix( vcs            ) :- print('VCS        '), !.
prefix( hyp_limit      ) :- print('HYP LIMIT EXCEEDED '), !.

%===============================================================================
% get_indentation(+D, -Indent).
%-------------------------------------------------------------------------------
% Calculate an indent as Indent given the current depth description as D.
%===============================================================================

get_indentation(toplevel, '') :- !.

get_indentation(D, Indent) :-
        already_know_indentation(D, Indent),
        !,
        print(Indent).

get_indentation(D, Indent) :-
        max_proof_framing_depth(M),
        Num5spaces is M-D,
        create_spaces(Num5spaces, Indent),
        !,
        assertz(already_know_indentation(D, Indent)),
        print(Indent).

%-------------------------------------------------------------------------------

create_spaces(1, '     ').
create_spaces(2, '          ').
create_spaces(3, '               ').
create_spaces(4, '                    ').
create_spaces(5, '                         ').
create_spaces(N, Indent) :-
        N > 5,
        Rest is N-5,
        create_spaces(Rest, R),
        name(R, L),
        append(L, "                         ", I),
        name(Indent, I),
        !.

create_spaces(_, '').           /* Otherwise -- shouldn't get here! */

%===============================================================================
% indent5.
%-------------------------------------------------------------------------------
% Write a five space indent.
%===============================================================================

indent5 :- print('     '), !.

%###############################################################################
% END-OF-FILE
