Coverage Summary for Class: ArgumentSearchModule (it.unibo.tuprolog.argumentation.core.modules.graph.partial)

Class Class, % Method, % Branch, % Line, % Instruction, %
ArgumentSearchModule 100% (1/1) 100% (3/3) 100% (3/3) 100% (7/7)


 package it.unibo.tuprolog.argumentation.core.modules.graph.partial
 
 import it.unibo.tuprolog.argumentation.core.modules.PrologModule
 
 /**
  * The arguments for a statement, built on demand (module `argumentSearch`, for query mode): from a premise, or from a
  * rule whose premises are supported in turn by the arguments for them (explored through the module
  * queryExploration, which saves them).
  *
  * An argument is the same term as the graph builder makes (see the module argumentBuilder): its rules and info from
  * those of its sub-arguments (argument::rulesAndInfo/5), its body the premises of its rule as written. Its parts are
  * collected in `found(Body, TopRule, Rules, Info, Supports)`, built in the clause bodies, so that clause heads only
  * match the conclusion or the premises (matching many arguments against every clause head is what makes resolution
  * expensive).
  */
 object ArgumentSearchModule : PrologModule("prolog.argumentation.structured.search", "argumentSearch") {
     override val prologRawTheory: String =
         // language=Prolog
         """
         %! findSingleArgument(+Conclusion, -Argument, -Supports)
         %  Argument is an argument for Conclusion, Supports its sub-arguments, saved.
         findSingleArgument(Conclusion, Argument, Supports) :-
             findArgument(Conclusion, found(Body, TopRule, Rules, Info, Supports)),
             argument::new(Rules, TopRule, Conclusion, Body, Info, Argument).
 
         % From a premise
         findArgument(Conclusion, Found) :-
             parser::classicRule(Id, Conclusion),
             premiseInfo(Id, Info),
             Found = found([], none, [Id], Info, []).
 
         % From a rule: an argument uses a rule at most once (argument::rulesAndInfo/5 fails otherwise)
         findArgument(Conclusion, Found) :-
             parser::classicRule(Id, Premises, Conclusion),
             findPremises(Premises, premises(Parts, Supports)),
             ruleStrictness(Id, Strict),
             argument::rulesAndInfo(Id, Strict, Parts, Rules, Info),
             Found = found(Premises, Id, Rules, Info, Supports).
 
         % The premises of a rule are supported one at a time, most selective first (see nextPremise/2): with the
         % bindings of the conclusion and of the premises supported so far, rather than in the order they are written,
         % which could build all the arguments for a premise that the following ones then discard. Each premise has a slot
         % for its result, and the results are collected in the order of the rule: an argument is the same however the
         % premises were supported.
         findPremises(Premises, Found) :-
             premiseSlots(Premises, Slots),
             supportPremises(Slots),
             collectPremises(Slots, Found).
 
         premiseSlots([], []).
         premiseSlots([Premise|Premises], [slot(Premise, _)|Slots]) :-
             premiseSlots(Premises, Slots).
 
         supportPremises(Slots) :-
             nextPremise(Slots, Slot), !,
             supportPremise(Slot),
             supportPremises(Slots).
         supportPremises(_).
 
         % The next premise to support: a Prolog check as soon as the ordinary premises written before it are supported
         % (with the bindings the graph builder gives it, as it may bind variables for the premises after it) or it is
         % ground (when it can only discard); otherwise the premise concluded by the fewest rules; the contrary premises,
         % which are only recorded, last
         nextPremise(Slots, Slot) :-
             readyCheck(Slots, true, Slot), !.
         nextPremise(Slots, Slot) :-
             mostSelective(Slots, none, best(Slot, _)), !.
         nextPremise(Slots, Slot) :-
             member(Slot, Slots),
             Slot = slot(_, Result),
             var(Result), !.
 
         % readyCheck(+Slots, +Supported, -Slot): the first pending Prolog check that can run, Supported telling whether
         % the ordinary premises before the slots are all supported
         readyCheck([Slot|_], Supported, Slot) :-
             Slot = slot(Premise, Result),
             var(Result),
             parser::prolog([Premise], _),
             (Supported == true ; ground(Premise)), !.
         readyCheck([slot(Premise, Result)|Slots], Supported, Slot) :-
             (var(Result), ordinaryPremise(Premise) -> Next = false ; Next = Supported),
             readyCheck(Slots, Next, Slot).
 
         % The pending ordinary premise concluded by the fewest rules: each count stops at the best one so far
         mostSelective([], Best, Best).
         mostSelective([Slot|Slots], Best, Selected) :-
             Slot = slot(Premise, Result),
             var(Result),
             ordinaryPremise(Premise), !,
             countLimit(Best, Limit),
             parser::candidates(Premise, Limit, Count),
             selective(Slot, Count, Best, Next),
             mostSelective(Slots, Next, Selected).
         mostSelective([_|Slots], Best, Selected) :-
             mostSelective(Slots, Best, Selected).
 
         countLimit(none, none).
         countLimit(best(_, Count), Count).
 
         selective(Slot, Count, none, best(Slot, Count)) :- !.
         selective(Slot, Count, best(_, Min), best(Slot, Count)) :- Count < Min, !.
         selective(_, _, Best, Best).
 
         ordinaryPremise(Premise) :-
             \+ parser::prolog([Premise], _),
             \+ parser::contrary([Premise], _).
 
         supportPremise(slot(Premise, Result)) :-
             parser::prolog([Premise], Term), !,
             (callable(Term) -> call(Term); Term),
             Result = check.
         supportPremise(slot(Premise, Result)) :-
             parser::contrary([Premise], _), !,
             Result = contrary.
         supportPremise(slot(Premise, Result)) :-
             argument::claim(Sub, _),
             queryExploration::buildSubGraph(Premise, Sub),
             Result = argument(Sub).
 
         % collectPremises(+Slots, -Premises): premises(Parts, Supports), the results of the slots: the rules, last
         % defeasible rules, defeasible rules and defeasible premises of the arguments for the premises (a list of lists
         % each, as argument::rulesAndInfo/5 takes them), and the arguments, in the order of the rule
         collectPremises([], Found) :-
             Found = premises([[], [], [], []], []).
         collectPremises([slot(_, check)|Slots], Found) :- !,
             collectPremises(Slots, Found).
         collectPremises([slot(_, contrary)|Slots], Found) :- !,
             collectPremises(Slots, Found).
         collectPremises([slot(_, argument(Sub))|Slots], Found) :-
             collectPremises(Slots, premises([Rules, LastDefRules, DefRules, DefPremises], Supports)),
             argument::rules(Sub, SubRules),
             argument::info(Sub, Info),
             argument::infoParts(Info, SubLastDefRules, SubDefRules, SubDefPremises),
             Found = premises(
                 [[SubRules|Rules], [SubLastDefRules|LastDefRules], [SubDefRules|DefRules], [SubDefPremises|DefPremises]],
                 [Sub|Supports]
             ).
 
         % The info of an argument made of the premise Id: none of its premises defeasible if it is strict
         premiseInfo(Id, Info) :- parser::checkStrict(Id), !, argument::infoParts(Info, [], [], []).
         premiseInfo(Id, Info) :- argument::infoParts(Info, [], [], [Id]).
 
         ruleStrictness(Id, strict) :- parser::checkStrict(Id), !.
         ruleStrictness(_, defeasible).
         """.trimIndent()
 }