Coverage Summary for Class: RuleGraph (it.unibo.tuprolog.argumentation.parallel.node)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| RuleGraph |
100%
(4/4)
|
50%
(1/2)
|
100%
(7/7)
|
98.1%
(53/54)
|
| RuleGraph$Arguments |
100%
(2/2)
|
75%
(3/4)
|
100%
(4/4)
|
100%
(68/68)
|
| RuleGraph$Attacks |
100%
(2/2)
|
75%
(3/4)
|
100%
(2/2)
|
100%
(27/27)
|
| Total |
100%
(8/8)
|
70%
(7/10)
|
100%
(13/13)
|
99.3%
(148/149)
|
package it.unibo.tuprolog.argumentation.parallel.node
import it.unibo.tuprolog.argumentation.core.modules.ArgLibrary
import it.unibo.tuprolog.argumentation.core.modules.Loadable
import it.unibo.tuprolog.argumentation.core.modules.ModuleRegistry
import it.unibo.tuprolog.argumentation.core.modules.PrologModule
import it.unibo.tuprolog.argumentation.core.runtime.Arg2pUnificator
import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Signature
import it.unibo.tuprolog.solve.primitive.Primitive
import it.unibo.tuprolog.solve.primitive.Solve
import it.unibo.tuprolog.solve.primitive.TernaryRelation
import it.unibo.tuprolog.solve.primitive.UnaryPredicate
/** The graph the workers of a catalog built, as the graph store saves it, for the modules of its solver */
internal interface BuiltGraph {
/**
* The arguments and their supports that [need] asks for (`whole`, the whole graph, or `explore(Statement)`, in query
* mode the arguments the labels of the arguments for Statement depend on), as lists of argument terms and of
* support/2 terms: null if the workers did not build them, which the catalog has them do
*/
fun arguments(need: Term): Pair<Term, Term>?
/** The direct attacks the workers found, as a list of attack/4 terms: none if they find none (with metaConflicts) */
val attacks: Term?
}
/**
* The modules of the solver of a catalog: those of the standard solver, but for the graph builder of the rules (the
* module ruleGraph) and query mode (queryExploration), which save the arguments and the attacks the workers built
* ([graph]) rather than build them
*/
internal fun graphModules(graph: BuiltGraph): List<ArgLibrary> {
val modules = listOf(RuleGraph(graph), QueryExploration)
val replaced = modules.map { it.identifier() }.toSet()
return modules + ModuleRegistry.all.filterNot { (it as? Loadable)?.identifier() in replaced }
}
// The graph builder of the rules: the arguments the workers built (a graph not built yet stops the resolution, see
// built/1), those derived from them (conflictArguments), and the attacks, those the workers found, which the graph
// store extends to the arguments built on the attacked ones, or all of them, by the module attackBuilder, if they
// find none
private class RuleGraph(
private val graph: BuiltGraph,
) : PrologModule("prolog.argumentation.parallel.graph", "ruleGraph") {
override val primitives: Map<Signature, Primitive>
get() = listOf(Arguments(), Attacks()).associate { it.descriptionPair }
override val prologRawTheory: String =
// language=Prolog
"""
%! buildArgumentationGraph
% The arguments the workers built, those derived from them, and the attacks between them.
buildArgumentationGraph :-
buildArguments,
buildAdditionalArguments,
buildAttacks.
%! buildArguments
% The arguments of the theory, built by the workers.
buildArguments :-
built(whole).
%! buildAdditionalArguments
% The arguments derived from the others (see the module conflictArguments).
buildAdditionalArguments :-
conflictArguments::buildAdditionalArguments.
%! buildAttacks
% The attacks between the saved arguments: the direct ones the workers found, extended by the graph store.
buildAttacks :-
builtAttacks(Attacks), !,
graphStore::saveAttacks(Attacks).
buildAttacks :-
attackBuilder::buildAttacks.
%! built(+Need)
% The arguments Need asks for (whole, or explore(Statement)) and their supports, saved as the workers built
% them; if they are not built yet, the resolution stops, to be started again once they are.
built(Need) :-
builtArguments(Need, Arguments, Supports), !,
graphStore::saveArguments(a, Arguments),
graphStore::saveSupports(Supports).
built(Need) :-
throw(not_built(Need)).
""".trimIndent()
// builtArguments(+Need, -Arguments, -Supports)
inner class Arguments : TernaryRelation.WithoutSideEffects<ExecutionContext>("builtArguments") {
override fun Solve.Request<ExecutionContext>.computeAllSubstitutions(
first: Term,
second: Term,
third: Term,
): Sequence<Substitution> =
graph.arguments(first)?.let { (arguments, supports) ->
unified(Struct.of("b", second, third), Struct.of("b", arguments, supports))
}
?: emptySequence()
}
// builtAttacks(-Attacks)
inner class Attacks : UnaryPredicate.WithoutSideEffects<ExecutionContext>("builtAttacks") {
override fun Solve.Request<ExecutionContext>.computeAllSubstitutions(first: Term): Sequence<Substitution> =
graph.attacks?.let { unified(first, it) } ?: emptySequence()
}
private fun unified(
first: Term,
second: Term,
) = Arg2pUnificator.mgu(first, second).let { if (it.isSuccess) sequenceOf(it) else emptySequence() }
}
// Query mode: the arguments the workers built exploring the query, as the module queryExploration explores it on its
// rules, and expanded as the locality of the semantics goes
private object QueryExploration : PrologModule("prolog.argumentation.parallel.exploration", "queryExploration") {
override val prologRawTheory: String =
// language=Prolog
"""
%! explore(+Query)
% The arguments for Query and those their labels may depend on, built by the workers.
explore(Query) :-
ruleGraph::built(explore(Query)).
%! expand(+Locality)
% Done by the workers, as they explore.
expand(_).
""".trimIndent()
}