Coverage Summary for Class: GraphMiningKt (it.unibo.tuprolog.argumentation.core.model.mining)

Class Class, % Method, % Branch, % Line, % Instruction, %
GraphMiningKt 100% (1/1) 100% (25/25) 80% (8/10) 100% (56/56) 98.6% (478/485)


 package it.unibo.tuprolog.argumentation.core.model.mining
 
 import it.unibo.tuprolog.argumentation.core.dsl.arg2pScope
 import it.unibo.tuprolog.argumentation.core.model.Argument
 import it.unibo.tuprolog.argumentation.core.model.Attack
 import it.unibo.tuprolog.argumentation.core.model.Graph
 import it.unibo.tuprolog.argumentation.core.model.LabelledArgument
 import it.unibo.tuprolog.argumentation.core.model.Support
 import it.unibo.tuprolog.argumentation.core.model.terms.ArgumentTerm
 import it.unibo.tuprolog.argumentation.core.model.terms.LabelTerm
 import it.unibo.tuprolog.core.Term
 import it.unibo.tuprolog.solve.Solver
 import kotlin.js.JsName
 
 // The graph of a context branch, read through graphStore: its arguments, their labels, attacks and supports
 
 /** The graph of the active context branch */
 @JsName("mineActiveGraph")
 fun Solver.graph(): Graph = graph(activeBranch())
 
 /** The graph of the context branch [context]: its arguments, labelled, their attacks and supports */
 @JsName("mineGraph")
 fun Solver.graph(context: Int): Graph =
     arguments(context).let {
         Graph.of(labels(context, it), attacks(context, it), supports(context, it))
     }
 
 /**
  * The arguments of the context branch [context], with the arguments supporting them ([Argument.supports]), identified
  * as A0, A1, ... in order of their number of supporters, rules, conclusion and top rule
  */
 @JsName("mineArguments")
 fun Solver.arguments(context: Int): List<Argument> {
     val arguments =
         arg2pScope {
             this@arguments
                 .solve("graphStore" call "argumentIn"(context, X))
                 .filter { it.isYes }
                 .map { Argument.of(it.substitution[X]!!) }
                 .toList()
         }
     supportsBetween(context, arguments).forEach { (supporter, supported) -> supported.supports.add(supporter) }
     // ordered by the conclusion as tuProlog writes it ('-'(a)), as arguments always were
     val claims = arguments.associateWith { ArgumentTerm.parts(it.termRepresentation())!!.claim.toString() }
     return arguments
         .sortedWith(compareBy({ it.supports.size }, { it.rules.size }, { claims.getValue(it) }, { it.topRule }))
         .onEachIndexed { index, argument -> argument.identifier = "A$index" }
 }
 
 /** The attacks between [arguments] in the context branch [context] */
 @JsName("mineAttacks")
 fun Solver.attacks(
     context: Int,
     arguments: List<Argument>,
 ): List<Attack> {
     if (arguments.isEmpty()) return emptyList()
     val lookup = arguments.lookup()
     return arg2pScope {
         this@attacks
             .solve("graphStore" call "attackIn"(context, T, X, Y, Z))
             .filter { it.isYes }
             .map {
                 Attack(
                     lookup.find(it.substitution[X]!!),
                     lookup.find(it.substitution[Y]!!),
                     it.substitution[T]!!.toString(),
                     // none for an attack on no sub-argument in particular
                     lookup.firstOrNull(it.substitution[Z]!!),
                 )
             }.toList()
     }
 }
 
 /** The supports between [arguments] in the context branch [context] */
 @JsName("mineSupports")
 fun Solver.supports(
     context: Int,
     arguments: List<Argument>,
 ): List<Support> = supportsBetween(context, arguments).map { (supporter, supported) -> Support(supporter, supported) }
 
 /** [arguments] with their labels in the context branch [context] (na, when an argument has none) */
 @JsName("mineLabels")
 fun Solver.labels(
     context: Int,
     arguments: List<Argument>,
 ): List<LabelledArgument> {
     val labelled =
         LabelTerm.labels.flatMap { label ->
             arg2pScope {
                 this@labels
                     .solve("graphStore" call "argumentLabelIn"(context, label, X))
                     .filter { it.isYes }
                     .map { Pair(it.substitution[X]!!, label) }
                     .toList()
             }
         }
     val labels = TermLookup(labelled) { it.first }
     return arguments.map { LabelledArgument(it, labels.firstOrNull(it.termRepresentation())?.second ?: "na") }
 }
 
 /** The number of the active context branch: the one of the last stage of the last resolution */
 @JsName("mineActiveBranch")
 fun Solver.activeBranch(): Int =
     arg2pScope {
         this@activeBranch
             .solve("context_active"(X))
             .filter { it.isYes }
             .map { it.substitution[X]!!.toString().toInt() }
             .firstOrNull()
     } ?: error("couldn't find a graph")
 
 // The pairs of supporter and supported argument, among [arguments], in the context branch [context]
 private fun Solver.supportsBetween(
     context: Int,
     arguments: List<Argument>,
 ): List<Pair<Argument, Argument>> {
     val lookup = arguments.lookup()
     return arg2pScope {
         this@supportsBetween
             .solve("graphStore" call "supportIn"(context, X, Y))
             .filter { it.isYes }
             .map { Pair(lookup.find(it.substitution[X]!!), lookup.find(it.substitution[Y]!!)) }
             .toList()
     }
 }
 
 private fun List<Argument>.lookup() = TermLookup(this) { it.termRepresentation() }
 
 private fun TermLookup<Argument>.find(term: Term) = firstOrNull(term) ?: throw NoSuchElementException("No argument matches $term")