Coverage Summary for Class: Explore (it.unibo.tuprolog.argumentation.parallel.message)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| Explore |
100%
(1/1)
|
100%
(1/1)
|
|
100%
(3/3)
|
100%
(12/12)
|
@file:Suppress("NON_EXPORTABLE_TYPE")
package it.unibo.tuprolog.argumentation.parallel.message
import it.unibo.tuprolog.argumentation.Answer
import it.unibo.tuprolog.argumentation.core.model.Graph
import it.unibo.tuprolog.core.Term
import kotlin.js.JsExport
import kotlin.js.JsName
import it.unibo.tuprolog.solve.Solution as LogicSolution
/**
* An argument for the statement evaluated ([claim], the statement), with the argument itself in [queryChain] (none
* for a statement no argument concludes), as Prolog text
*/
@JsExport
data class Response(
val claim: String,
@JsExport.Ignore @JsName("queryChainList") val queryChain: List<String>,
) {
/** The argument, as Prolog text (an array in JavaScript) */
@JsName("queryChain")
val queryChainArray: Array<String> get() = queryChain.toTypedArray()
}
/**
* An argument, by its global identifier ([id], the worker that built it and its identifier there), with the identifiers
* of the arguments it rests on directly ([supports], from a worker to the catalog only)
*/
internal data class SharedArgument(
val id: String,
val argument: Term,
val supports: List<String> = emptyList(),
)
/** The premises of the rules of [worker], and their conclusions */
internal data class Interest(
val worker: Int,
val premises: List<Term>,
val conclusions: List<Term>,
)
/** A direct attack of type [type] of the argument [attacker] on the argument [target], by their global identifiers */
internal data class DirectAttack(
val type: String,
val attacker: String,
val target: String,
)
/**
* The messages between the nodes of a distributed solver: the catalog, the workers and the clients, each known by its
* address (see [Address]). On a machine the terms travel as they are (they are immutable, shared by the nodes
* without copies); the transports between processes write them as Prolog text (see [MessageCodec]).
*
* After a change of the theory, the first evaluation builds the graph:
* 1. the catalog sends each worker its rules and the flags ([Load]); each tells the premises and the conclusions of
* its rules ([Subscribe]);
* 2. the catalog sends every worker those of all ([Build]). On the whole graph, each builds the arguments of its rules,
* sends them to the workers whose rules use their conclusions ([Notify]), which build on them in turn, and
* publishes them to the catalog ([Publish]). In query mode, the arguments the evaluations depend on alone, as the
* standard solver explores them (see the module queryExploration): the catalog asks the workers concluding the
* statements evaluated to explore them ([Explore]); each explores them on its rules, asks the others for the
* statements its exploration needs and its rules do not conclude, and sends what it builds to those that asked for
* it. Every Build, Explore, Notify and Publish is acknowledged to its sender ([Ack]); a worker acknowledges the
* message that engaged it only once all it sent is acknowledged (Dijkstra and Scholten): with every Build and
* Explore acknowledged, the arguments are all built and published;
* 3. the workers find the attacks ([Attack]): each tells the others the statements that may attack its arguments
* ([Wanted]), sends each the arguments of its own for them ([Candidates]), finds the direct attacks on its own and
* sends them to the catalog ([AttacksFound]), which extends them to the arguments built on the attacked ones and
* labels the graph.
*
* In query mode a later evaluation needing more of the graph explores it further ([Explore]), then the attacks are
* found again.
*
* The goals of the clients ([RequireSolution], [RequireAnswer], [RequireEvaluation]) are solved by the catalog, on the
* graph the workers built for them as above (see Catalog).
*/
sealed interface KbMessage
/** To the catalog: forget the theory */
internal data object Reset : KbMessage
/** To the catalog: a graph being built lost some of its workers (a site left), build it again with those left */
internal data object Rebuild : KbMessage
/**
* To the catalog: the evaluations of the clients were stopped (they were told already), give up the graph being built
* for them; nothing to do if none was
*/
internal data object Stop : KbMessage
/** To the catalog: the flags of the solver, as Prolog facts, for the evaluations from now on (the graph built anew) */
internal data class Configure(
val flags: String,
) : KbMessage
/**
* To the catalog: the whole theory, as Prolog text, partitioned among the workers (see TheoryPartitioner); to a
* worker: its part of the theory, replacing the one it had, and the [flags] of the solver, as Prolog facts
*/
internal data class Load(
val theory: String,
val flags: String = "",
) : KbMessage
/** To the catalog: a clause more for the theory, as Prolog text */
internal data class Add(
val elem: String,
) : KbMessage
/** To the catalog: the labels of the arguments for the statement [elem], to send to the client [replyTo] */
internal data class RequireEvaluation(
val elem: String,
val replyTo: String,
) : KbMessage
/** To a client: the arguments for the statement it asked about, by label, or the [error] that kept it from an answer */
@JsExport
data class EvaluationResponse(
@JsExport.Ignore @JsName("inArgsList") val inArgs: List<Response>,
@JsExport.Ignore @JsName("outArgsList") val outArgs: List<Response>,
@JsExport.Ignore @JsName("undArgsList") val undArgs: List<Response>,
val error: String? = null,
) : KbMessage {
/** The arguments labelled in (an array in JavaScript) */
@JsName("inArgs")
val inArray: Array<Response> get() = inArgs.toTypedArray()
/** The arguments labelled out (an array in JavaScript) */
@JsName("outArgs")
val outArray: Array<Response> get() = outArgs.toTypedArray()
/** The arguments labelled und (an array in JavaScript) */
@JsName("undArgs")
val undArray: Array<Response> get() = undArgs.toTypedArray()
}
/**
* To the catalog: the next solution of the goal the client solves in [run], to send to the client [replyTo]; [goal], as
* Prolog text, for the first one
*/
internal data class RequireSolution(
val run: String,
val goal: String?,
val replyTo: String,
) : KbMessage
/** To the catalog: the statements for [query], as Prolog text, by label (see answerQuery/4), to send to the client [replyTo] */
internal data class RequireAnswer(
val query: String,
val replyTo: String,
) : KbMessage
/**
* To a client: a solution of the goal of [run] (none if it has no more), the graph of its resolution, whether the goal
* has more solutions, and what the solver printed computing it; or the [error] that kept it from one (a goal that
* cannot be read, a theory that cannot be read); or, [stopped], none as the evaluation was stopped. Only for the
* clients of the site of the catalog: never written.
*/
internal data class SolutionResponse(
val run: String,
val solution: LogicSolution?,
val graph: Graph,
val hasNext: Boolean,
val output: String,
val error: String? = null,
val stopped: Boolean = false,
) : KbMessage
/** The graph of a solution that labels none */
internal val NO_GRAPH = Graph(emptyList(), emptyList(), emptyList())
/** Why an evaluation stopped by its client has no answer */
internal const val STOPPED = "The evaluation was stopped"
/** To a client: the [answer] of a query, or the [error] that kept it from one. Only for the clients of the site of the catalog: never written. */
internal data class AnswerResponse(
val answer: Answer?,
val error: String? = null,
) : KbMessage
/** To the catalog: the statements the rules of [worker] use as premises, whose arguments it needs, and conclude */
internal data class Subscribe(
val worker: Int,
val premises: List<Term>,
val conclusions: List<Term>,
) : KbMessage
/**
* To a worker: the graph is to be built, [interests] the premises and conclusions of every worker. With no [locality],
* the arguments of all its rules; otherwise (query mode, directional or connected) those [Explore] asks for alone.
*/
internal data class Build(
val interests: List<Interest>,
val locality: String? = null,
) : KbMessage
/**
* To a worker, from the catalog ([from] -1) or another worker: explore [statements] on its rules, as the standard solver
* explores a query (see the module queryExploration), and send the arguments for them to the sender
*/
internal data class Explore(
val from: Int,
val statements: List<Term>,
) : KbMessage
/** To a worker: arguments of the worker [from] for the premises of its rules, to build on */
internal data class Notify(
val from: Int,
val arguments: List<SharedArgument>,
) : KbMessage
/** To the catalog: the arguments [worker] built, with their supports */
internal data class Publish(
val worker: Int,
val arguments: List<SharedArgument>,
) : KbMessage
/** To the sender of a Build, an Explore, a Notify or a Publish: it is handled, and so is all it led to; [from] is -1 for the catalog */
internal data class Ack(
val from: Int,
) : KbMessage
/** To a worker: the arguments are all built, find the attacks on its own */
internal data object Attack : KbMessage
/** To another worker: the statements whose arguments may attack those of [worker] */
internal data class Wanted(
val worker: Int,
val statements: List<Term>,
) : KbMessage
/**
* To another worker: the arguments of [worker] for the statements it wants, as much of them as an attack needs (their
* top rules, conclusions, bodies and info, not their rules)
*/
internal data class Candidates(
val worker: Int,
val arguments: List<SharedArgument>,
) : KbMessage
/** To the catalog: the direct attacks on the arguments of [worker] */
internal data class AttacksFound(
val worker: Int,
val attacks: List<DirectAttack>,
) : KbMessage
/** The addresses of the nodes of a distributed solver */
internal object Address {
/** The catalog, holding the theory, partitioning it and gathering the graph */
const val CATALOG = "catalog"
private const val WORKER = "worker_"
/** The worker of the partition [index] */
fun worker(index: Int) = "$WORKER$index"
/** Whether [address] is the one of a worker */
fun isWorker(address: String) = address.startsWith(WORKER)
/** The index of the partition of the worker at [address] */
fun indexOf(address: String) = address.removePrefix(WORKER).toInt()
}