Coverage Summary for Class: QueryExplorationModule (it.unibo.tuprolog.argumentation.core.modules.graph.partial)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| QueryExplorationModule |
100%
(1/1)
|
100%
(4/4)
|
|
100%
(4/4)
|
100%
(13/13)
|
package it.unibo.tuprolog.argumentation.core.modules.graph.partial
import it.unibo.tuprolog.argumentation.core.modules.PrologModule
import it.unibo.tuprolog.argumentation.core.primitives.graph.partial.GroundVars
import it.unibo.tuprolog.solve.Signature
import it.unibo.tuprolog.solve.primitive.Primitive
/**
* The part of the argumentation graph a query depends on (module `queryExploration`, for query mode): the arguments
* for the query, and, recursively, those their labels may depend on, saved as they are built (see the module
* argumentSearch).
*/
object QueryExplorationModule : PrologModule("prolog.argumentation.structured.exploration", "queryExploration") {
override val primitives: Map<Signature, Primitive>
get() = mapOf(GroundVars.descriptionPair)
override val prologRawTheory: String =
// language=Prolog
"""
%! explore(+Query)
% The arguments for Query and those their labels may depend on (see exploreStatement/2). With cycles among the
% rules, a statement needed as a premise while its arguments are being built only gets those built so far: the
% exploration is then repeated, from scratch, until it builds no new argument (the arguments are finitely many,
% as none uses a rule twice).
explore(Query) :-
graphStore::forgetNewConclusions(query),
context_retract(cycle),
exploreStatement(Query, dependency),
(context_check(cycle), graphStore::newConclusion(query, _) ->
context_retract(explored(_)),
explore(Query)
;
true
).
% A solver given arguments built elsewhere (as a worker of the parallel solver, which has some of the rules) carries
% on its exploration as they come: resume/1 explores again what they may support, restart/0 forgets it all.
%! resume(+Statements)
% The exploration carried on once arguments for Statements are saved: the statements explored whose rules use
% them as premises, directly or through other statements, explored again, the others left as they are.
resume(Statements) :-
builtOn(Statements, [], Affected),
findall(_, (member(S, Affected), context_retract(explored(S))), _),
findall(_, (member(S, Affected), explore(S)), _).
%! restart
% The exploration forgotten, not the arguments it built: exploring again finds all that the arguments saved
% since support or make possible attackers (with metaConflicts, those for conflicts).
restart :-
context_retract(explored(_)),
context_retract(expanded(_)),
attackCandidates::forgetPossibleAttackers.
% builtOn(+Statements, +Seen, -Affected): the statements explored whose rules use one of Statements as a premise,
% as they were explored (q(X), rather than the instance q(1) of the rule using p(1)), and in turn those whose
% rules use them; Seen are those found so far (with groundVars/2)
builtOn([], _, []).
builtOn([Statement|Statements], Seen, Affected) :-
findall(S, (parser::ruleUsing(Statement, C), exploredAs(C, S)), Found),
unseen(Found, Seen, New, Seen1),
utils::appendLists([Statements, New], Next),
builtOn(Next, Seen1, Rest),
utils::appendLists([New, Rest], Affected).
% exploredAs(+Statement, -Explored): Explored is explored and unifies with Statement, as it was explored
exploredAs(Statement, Explored) :-
context_check(explored(Explored)),
\+ \+ Explored = Statement.
unseen([], Seen, [], Seen).
unseen([S|Ss], Seen, New, Seen1) :-
groundVars(S, N),
(member(N, Seen) ->
unseen(Ss, Seen, New, Seen1)
;
New = [S|New1],
unseen(Ss, [N|Seen], New1, Seen1)
).
%! explored(?Statement)
% Statement is explored (with the statements it generalises).
explored(Statement) :-
context_check(explored(Statement)).
%! premiseOfExplored(?Premise)
% Premise is one of the premises, to be supported by an argument, of a rule concluding a statement explored, and
% the statement makes it ground. The exploration supports the premises one at a time, the next once the one
% before is, with its bindings: a solver whose arguments for them are built elsewhere asks for the ground ones
% all at once, so that they are built side by side (the bindings of the others leave them as they are).
premiseOfExplored(Premise) :-
context_check(explored(Statement)),
parser::classicRule(_, Premises, [Statement]),
member(Premise, Premises),
ground(Premise),
parser::argued(Premise).
%! exploreAll(+Queries)
% Each of Queries explored (see explore/1).
exploreAll(Queries) :-
findall(_, (member(Query, Queries), explore(Query)), _).
%! buildSubGraph(+Query, ?Argument)
% Argument is each argument for Query, a premise, once explored.
buildSubGraph(Query, Argument) :-
exploreStatement(Query, premise),
graphStore::argumentFor([Query], Argument).
% exploreStatement(+Query, +Use): builds the arguments for Query, and those their labels may depend on (see
% dependency/3), recursively, unless it is explored (once, or once more for each round of explore/1):
% explored(Query) covers the statements Query generalises. A statement met again while it is being explored only
% has the arguments built so far: needed as a premise (Use), that is a cycle; needed as a dependency, its
% exploration under way builds them all.
exploreStatement(Query, _) :-
groundVars(Query, Normalized),
context_absent(explored(Normalized)), !,
context_assert(explored(Query)),
context_assert(exploring(Normalized, Query)),
findall(_, (
argumentSearch::findSingleArgument([Query], Argument, Supports),
recordArgument(Query, Argument, Supports),
graphStore::argumentId(Argument, Id),
dependency(Id, Argument, Statement),
exploreStatement(Statement, dependency)
), _),
context_retract(exploring(Normalized, _)).
exploreStatement(Query, premise) :-
groundVars(Query, Normalized),
context_check(exploring(_, Normalized)), !,
(context_absent(cycle) -> context_assert(cycle) ; true).
exploreStatement(_, _).
% The statements whose arguments the label of an argument may depend on, besides its sub-arguments (built with
% it): those that make others conflict with it (metaConflicts), those of its possible attackers, and those the
% graph extensions relate it to. The conflicts come first, as the possible attackers are only looked for once.
dependency(_, Argument, S) :- attackCandidates::attackDependency(Argument, S).
dependency(Id, Argument, S) :- attackCandidates::possibleAttackers(Id, Argument, [S]).
dependency(_, Argument, S) :- setting(graphExtension, X), X::queryDependencies(Argument, S).
%! expand(+Locality)
% For the connected locality, the arguments whose labels may depend on the ones built (see dependant/2), with
% those they depend on in turn, until none is new.
expand(connected) :-
findall(Id, (graphStore::argumentById(Id, _), context_absent(expanded(Id))), Ids),
Ids \== [], !,
findall(_, (
member(Id, Ids),
context_assert(expanded(Id)),
graphStore::argumentById(Id, Argument),
dependant(Argument, Statement),
explore(Statement)
), _),
expand(connected).
expand(_).
% The statements whose arguments may depend on an argument: those it may attack, those its conclusion makes
% conflict (metaConflicts), those of its super-arguments, and those the graph extensions relate to it
dependant(Argument, S) :- attackCandidates::possiblyAttacked(Argument, S).
dependant(Argument, S) :- attackCandidates::attackDependant(Argument, S).
dependant(Argument, S) :-
argument::claim(Argument, Claim),
parser::ruleUsing(Claim, S).
dependant(Argument, S) :- setting(graphExtension, X), X::queryDependants(Argument, S).
% recordArgument(+Query, +Argument, +Supports): Argument saved with its supports, unless it already was (built in
% a previous round of explore/1, whose dependencies are explored again)
recordArgument(Query, Argument, Supports) :-
graphStore::saveArgument(query, [Query], Argument), !,
saveSupports(Argument, Supports).
recordArgument(_, _, _).
saveSupports(_, []).
saveSupports(Argument, [Support|Supports]) :-
graphStore::saveSupport(Support, Argument),
saveSupports(Argument, Supports).
""".trimIndent()
}