mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 06:14:59 +00:00
Estimated hours taken: 10
Represent bugs directly rather than with edt nodes. This makes the
interface to the analyser more consistent: bugs are now handled
in much the same way as questions.
browser/declarative_analyser.m:
- In the mercury_edt/2 typeclass, change edt_root/3 to
edt_root_question/3 and add the method edt_root_e_bug/3.
- Add the type prime_suspect/1 which keeps track of the
evidence (oracle answers) which implicates a particular
edt node.
- Use the new bug representation.
browser/declarative_debugger.m:
browser/declarative_oracle.m:
- Move oracle_confirmation to declarative_debugger.m, and
rename it decl_confirmation.
browser/declarative_debugger.m:
- Change decl_bug/1 to decl_bug/0. Instead of a bug being
represented by an edt node, decl_bug now represents
directly the different sorts of bugs possible.
- Add an implementation for the new mercury_edt method.
browser/declarative_oracle.m:
browser/declarative_user.m:
- Update the confirmation to use the new types.
tests/debugger/declarative/*.{exp,exp2}:
- Update test results.
277 lines
8.5 KiB
Mathematica
277 lines
8.5 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2000 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: declarative_oracle.m
|
|
% Author: Mark Brown
|
|
% Purpose:
|
|
% This module implements the oracle for a Mercury declarative debugger.
|
|
% It is called by the front end of the declarative debugger to provide
|
|
% information about the intended interpretation of the program being
|
|
% debugged.
|
|
%
|
|
% The module has a knowledge base as a sub-component. This is a cache
|
|
% for all the assumptions that the oracle is currently making. When
|
|
% the oracle is queried, it first checks the KB to see if an answer
|
|
% is available there.
|
|
%
|
|
% If no answer is available in the KB, then the oracle uses the UI
|
|
% (in browser/declarative_user.m) to get the required answer from the
|
|
% user. If any new knowledge is obtained, it is added to the KB so
|
|
% the user will not be asked the same question twice.
|
|
%
|
|
|
|
:- module mdb__declarative_oracle.
|
|
:- interface.
|
|
:- import_module mdb__declarative_debugger.
|
|
:- import_module list, io.
|
|
|
|
% A response that the oracle gives to a query about the
|
|
% truth of an EDT node.
|
|
%
|
|
:- type oracle_response
|
|
---> oracle_answers(list(decl_answer))
|
|
; no_oracle_answers
|
|
; abort_diagnosis.
|
|
|
|
% The oracle state. This is threaded around the declarative
|
|
% debugger.
|
|
%
|
|
:- type oracle_state.
|
|
|
|
% Produce a new oracle state.
|
|
%
|
|
:- pred oracle_state_init(io__input_stream, io__output_stream, oracle_state).
|
|
:- mode oracle_state_init(in, in, out) is det.
|
|
|
|
% Query the oracle about the program being debugged. The first
|
|
% argument is a queue of nodes in the evaluation tree, the second
|
|
% argument is the oracle response to any of these. The oracle
|
|
% state is threaded through so its contents can be updated after
|
|
% user responses.
|
|
%
|
|
:- pred query_oracle(list(decl_question), oracle_response, oracle_state,
|
|
oracle_state, io__state, io__state).
|
|
:- mode query_oracle(in, out, in, out, di, uo) is det.
|
|
|
|
% Confirm that the node found is indeed an e_bug or an i_bug.
|
|
%
|
|
:- pred oracle_confirm_bug(decl_bug, decl_confirmation, oracle_state,
|
|
oracle_state, io__state, io__state).
|
|
:- mode oracle_confirm_bug(in, out, in, out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module mdb__declarative_user, mdb__util.
|
|
:- import_module bool, std_util, map, set, require.
|
|
|
|
query_oracle(Queries, Response, Oracle0, Oracle) -->
|
|
{ get_oracle_kb(Oracle0, KB0) },
|
|
{ list__filter_map(query_oracle_kb(KB0), Queries, Answers) },
|
|
(
|
|
{ Answers = [] }
|
|
->
|
|
{ get_oracle_user(Oracle0, User0) },
|
|
query_user(Queries, UserResponse, User0, User),
|
|
{
|
|
UserResponse = user_answer(Answer),
|
|
assert_oracle_kb(Answer, KB0, KB),
|
|
Response = oracle_answers([Answer])
|
|
;
|
|
UserResponse = no_user_answer,
|
|
Response = no_oracle_answers,
|
|
KB = KB0
|
|
;
|
|
UserResponse = abort_diagnosis,
|
|
Response = abort_diagnosis,
|
|
KB = KB0
|
|
},
|
|
{ set_oracle_kb(Oracle0, KB, Oracle1) },
|
|
{ set_oracle_user(Oracle1, User, Oracle) }
|
|
;
|
|
{ Response = oracle_answers(Answers) },
|
|
{ Oracle = Oracle0 }
|
|
).
|
|
|
|
oracle_confirm_bug(Bug, Confirmation, Oracle0, Oracle) -->
|
|
{ get_oracle_user(Oracle0, User0) },
|
|
user_confirm_bug(Bug, Confirmation, User0, User),
|
|
{ set_oracle_user(Oracle0, User, Oracle) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type oracle_state
|
|
---> oracle(
|
|
oracle_kb, % Knowledge base.
|
|
user_state % User interface.
|
|
).
|
|
|
|
oracle_state_init(InStr, OutStr, Oracle) :-
|
|
user_state_init(InStr, OutStr, User),
|
|
oracle_kb_init(KB),
|
|
Oracle = oracle(KB, User).
|
|
|
|
:- pred get_oracle_kb(oracle_state, oracle_kb).
|
|
:- mode get_oracle_kb(in, out) is det.
|
|
|
|
get_oracle_kb(oracle(KB, _), KB).
|
|
|
|
:- pred set_oracle_kb(oracle_state, oracle_kb, oracle_state).
|
|
:- mode set_oracle_kb(in, in, out) is det.
|
|
|
|
set_oracle_kb(oracle(_, UI), KB, oracle(KB, UI)).
|
|
|
|
:- pred get_oracle_user(oracle_state, user_state).
|
|
:- mode get_oracle_user(in, out) is det.
|
|
|
|
get_oracle_user(oracle(_, UI), UI).
|
|
|
|
:- pred set_oracle_user(oracle_state, user_state, oracle_state).
|
|
:- mode set_oracle_user(in, in, out) is det.
|
|
|
|
set_oracle_user(oracle(KB, _), UI, oracle(KB, UI)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% This section implements the oracle knowledge base, which
|
|
% stores anything that the debugger knows about the intended
|
|
% interpretation. This can be used to check the correctness
|
|
% of an EDT node.
|
|
%
|
|
|
|
% The type of the knowledge base. Other fields may be added in
|
|
% the future, such as for assertions made on-the-fly by the user,
|
|
% or assertions in the program text.
|
|
%
|
|
:- type oracle_kb
|
|
---> oracle_kb(
|
|
|
|
% For ground atoms, the knowledge is represented directly
|
|
% with a map. This is used, for example, in the common
|
|
% case that the user supplies a truth value for a
|
|
% "wrong answer" node.
|
|
%
|
|
map(decl_atom, decl_truth),
|
|
|
|
% Mapping from call atoms to their solution sets.
|
|
% The sets in this map are all complete---but they may
|
|
% contain wrong answers.
|
|
%
|
|
map(decl_atom, set(decl_atom)),
|
|
|
|
% Mapping from call atoms to their solution sets.
|
|
% The sets in this map are all incomplete---there
|
|
% exists a correct solution which is not in the set.
|
|
%
|
|
map(decl_atom, set(decl_atom))
|
|
).
|
|
|
|
:- pred oracle_kb_init(oracle_kb).
|
|
:- mode oracle_kb_init(out) is det.
|
|
|
|
oracle_kb_init(oracle_kb(G, Y, N)) :-
|
|
map__init(G),
|
|
map__init(Y),
|
|
map__init(N).
|
|
|
|
:- pred get_kb_ground_map(oracle_kb, map(decl_atom, decl_truth)).
|
|
:- mode get_kb_ground_map(in, out) is det.
|
|
|
|
get_kb_ground_map(oracle_kb(Map, _, _), Map).
|
|
|
|
:- pred set_kb_ground_map(oracle_kb, map(decl_atom, decl_truth), oracle_kb).
|
|
:- mode set_kb_ground_map(in, in, out) is det.
|
|
|
|
set_kb_ground_map(oracle_kb(_, Y, N), G, oracle_kb(G, Y, N)).
|
|
|
|
:- pred get_kb_complete_map(oracle_kb, map(decl_atom, set(decl_atom))).
|
|
:- mode get_kb_complete_map(in, out) is det.
|
|
|
|
get_kb_complete_map(oracle_kb(_, Map, _), Map).
|
|
|
|
:- pred set_kb_complete_map(oracle_kb, map(decl_atom, set(decl_atom)),
|
|
oracle_kb).
|
|
:- mode set_kb_complete_map(in, in, out) is det.
|
|
|
|
set_kb_complete_map(oracle_kb(G, _, N), Y, oracle_kb(G, Y, N)).
|
|
|
|
:- pred get_kb_incomplete_map(oracle_kb, map(decl_atom, set(decl_atom))).
|
|
:- mode get_kb_incomplete_map(in, out) is det.
|
|
|
|
get_kb_incomplete_map(oracle_kb(_, _, Map), Map).
|
|
|
|
:- pred set_kb_incomplete_map(oracle_kb, map(decl_atom, set(decl_atom)),
|
|
oracle_kb).
|
|
:- mode set_kb_incomplete_map(in, in, out) is det.
|
|
|
|
set_kb_incomplete_map(oracle_kb(G, Y, _), N, oracle_kb(G, Y, N)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred query_oracle_kb(oracle_kb, decl_question, decl_answer).
|
|
:- mode query_oracle_kb(in, in, out) is semidet.
|
|
|
|
query_oracle_kb(KB, Node, Node - Truth) :-
|
|
Node = wrong_answer(Atom),
|
|
get_kb_ground_map(KB, Map),
|
|
map__search(Map, Atom, Truth).
|
|
|
|
query_oracle_kb(KB, Node, Node - Truth) :-
|
|
Node = missing_answer(Call, Solns),
|
|
set__list_to_set(Solns, Ss),
|
|
get_kb_complete_map(KB, CMap),
|
|
(
|
|
map__search(CMap, Call, CSs),
|
|
set__subset(CSs, Ss)
|
|
->
|
|
Truth = yes
|
|
;
|
|
get_kb_incomplete_map(KB, IMap),
|
|
map__search(IMap, Call, ISs),
|
|
set__subset(Ss, ISs),
|
|
Truth = no
|
|
).
|
|
|
|
% assert_oracle_kb/3 assumes that the asserted fact is consistent
|
|
% with the current knowledge base. This will generally be the
|
|
% case, since the user will never be asked questions which
|
|
% the knowledge base knows anything about.
|
|
%
|
|
:- pred assert_oracle_kb(decl_answer, oracle_kb, oracle_kb).
|
|
:- mode assert_oracle_kb(in, in, out) is det.
|
|
|
|
assert_oracle_kb(wrong_answer(Atom) - Truth, KB0, KB) :-
|
|
get_kb_ground_map(KB0, Map0),
|
|
map__det_insert(Map0, Atom, Truth, Map),
|
|
set_kb_ground_map(KB0, Map, KB).
|
|
|
|
assert_oracle_kb(missing_answer(Call, Solns) - yes, KB0, KB) :-
|
|
get_kb_complete_map(KB0, Map0),
|
|
set__list_to_set(Solns, Ss0),
|
|
(
|
|
map__search(Map0, Call, OldSs)
|
|
->
|
|
% The sets are both complete, so their
|
|
% intersection must be also.
|
|
%
|
|
set__intersect(OldSs, Ss0, Ss),
|
|
map__set(Map0, Call, Ss, Map)
|
|
;
|
|
map__det_insert(Map0, Call, Ss0, Map)
|
|
),
|
|
set_kb_complete_map(KB0, Map, KB).
|
|
|
|
assert_oracle_kb(missing_answer(Call, Solns) - no, KB0, KB) :-
|
|
get_kb_incomplete_map(KB0, Map0),
|
|
set__list_to_set(Solns, Ss),
|
|
%
|
|
% XXX should also keep the old incomplete set around, too.
|
|
% It can still give us information that the new one can't.
|
|
%
|
|
map__set(Map0, Call, Ss, Map),
|
|
set_kb_incomplete_map(KB0, Map, KB).
|
|
|