Package-level declarations

Types

Link copied to clipboard
interface AtomicInt

A tiny, multiplatform abstraction over a mutable integer counter that multiple coroutines may update concurrently. ConcurrentResolutionHandle uses it as ConcurrentResolutionHandle.solutionCounter, to count how many solutions have been produced so far by the many coroutines exploring a goal's search tree in parallel, so that resolution can be stopped once it.unibo.tuprolog.solve.SolveOptions.limit is reached.

Link copied to clipboard
class AtomicIntJs(var value: Int) : AtomicInt

The Kotlin/JS AtomicInt implementation: a plain, non-atomic var. Safe only because JS coroutines are cooperatively scheduled on a single thread and never preempted mid-operation, not a general-purpose atomic counter.

Link copied to clipboard

The JVM AtomicInt implementation, delegating every operation to a java.util.concurrent.atomic.AtomicInteger.

Link copied to clipboard
data class ConcurrentExecutionContext(val procedure: Struct? = null, val unificator: Unificator = Unificator.default, val libraries: Runtime = Runtime.empty(), val flags: FlagStore = FlagStore.empty(), val staticKb: Theory = Theory.empty(unificator), val dynamicKb: MutableTheory = MutableTheory.empty(unificator), val operators: OperatorSet = getAllOperators(libraries, staticKb, dynamicKb).toOperatorSet(), val inputChannels: InputStore = InputStore.fromStandard(), val outputChannels: OutputStore = OutputStore.fromStandard(), val customData: CustomDataStore = CustomDataStore.empty(), val substitution: Substitution.Unifier = Substitution.empty(), val query: Struct = Truth.TRUE, val goals: Cursor<out Term> = Cursor.empty(), val rule: Rule? = null, val primitive: Solve.Response? = null, val startTime: TimeInstant, val maxDuration: TimeDuration = TimeDuration.MAX_VALUE, val parent: ConcurrentExecutionContext? = null, val depth: Int = 0, val step: Long = 0) : ExecutionContext

The ExecutionContext implementation for :solve-concurrent: an immutable node of the resolution tree that it.unibo.tuprolog.solve.concurrent.fsm.States carry around and derive from, chained back to the root goal via parent. Each concurrently-running coroutine spawned while resolving a goal (see ConcurrentSolver) owns its own chain of these, so no synchronization is needed to read pathToRoot/logicStackTrace from within a single branch -- only knowledge-base mutation shared across branches (see ConcurrentSolver's concurrency caveat) is unsynchronized.

Link copied to clipboard
data class ConcurrentResolutionHandle(val solveOptions: SolveOptions, val solutionChannel: SendChannel<Solution>, val solutionCounter: AtomicInt = AtomicInt.zero())

The piece of shared, cross-coroutine state that lets the many concurrently-running branches of a single :solve-concurrent resolution (see ConcurrentSolver.solveConcurrently) agree on a single solutionChannel to publish Solutions to, and on when enough solutions have been produced to stop exploring the search tree altogether.

Link copied to clipboard

A Solver whose resolution strategy explores the alternatives of a goal's search tree -- matching clauses at a choice point, the branches of a disjunction, the several solutions of a backtracking primitive -- concurrently, as independent Kotlin coroutines, rather than one at a time as :solve-classic/:solve-streams do. Obtained via ConcurrentSolverFactory or, generically, via it.unibo.tuprolog.solve.Solver.concurrent.

Link copied to clipboard

The SolverFactory for :solve-concurrent, backing it.unibo.tuprolog.solve.Solver.concurrent: every Solver/MutableSolver it produces is a ConcurrentSolver that resolves goals by running the alternatives of the search tree (matching clauses, disjunction branches, backtracking primitive solutions) as concurrent Kotlin coroutines rather than one at a time -- see ConcurrentSolver for the resulting caveats around solution ordering and concurrent knowledge-base mutation.

Functions

Link copied to clipboard
expect fun closeExecution()

Blocks (on the JVM) until the thread pools backing createScope/backgroundScope have finished executing every pending coroutine, then shuts them down. Called once at the end of ConcurrentResolutionHandle.terminateResolution, after a resolution's solution limit has been reached, to make sure no orphaned coroutine keeps running (or holding threads) past that point.

actual fun closeExecution()

Blocks (on the JVM) until the thread pools backing createScope/backgroundScope have finished executing every pending coroutine, then shuts them down. Called once at the end of ConcurrentResolutionHandle.terminateResolution, after a resolution's solution limit has been reached, to make sure no orphaned coroutine keeps running (or holding threads) past that point.

actual fun closeExecution()

Blocks (on the JVM) until the thread pools backing createScope/backgroundScope have finished executing every pending coroutine, then shuts them down. Called once at the end of ConcurrentResolutionHandle.terminateResolution, after a resolution's solution limit has been reached, to make sure no orphaned coroutine keeps running (or holding threads) past that point.

Link copied to clipboard
expect fun createScope(): CoroutineScope

Creates a fresh, platform-specific CoroutineScope to run one :solve-concurrent resolution in -- one call per ConcurrentSolver.solveConcurrently invocation, so that cancelling the scope (e.g. once it.unibo.tuprolog.solve.SolveOptions.limit is hit, see ConcurrentResolutionHandle.terminateResolution) only affects the coroutines spawned for that particular resolution.

actual fun createScope(): CoroutineScope

Creates a fresh, platform-specific CoroutineScope to run one :solve-concurrent resolution in -- one call per ConcurrentSolver.solveConcurrently invocation, so that cancelling the scope (e.g. once it.unibo.tuprolog.solve.SolveOptions.limit is hit, see ConcurrentResolutionHandle.terminateResolution) only affects the coroutines spawned for that particular resolution.

actual fun createScope(): CoroutineScope

Creates a fresh, platform-specific CoroutineScope to run one :solve-concurrent resolution in -- one call per ConcurrentSolver.solveConcurrently invocation, so that cancelling the scope (e.g. once it.unibo.tuprolog.solve.SolveOptions.limit is hit, see ConcurrentResolutionHandle.terminateResolution) only affects the coroutines spawned for that particular resolution.

Link copied to clipboard
expect fun <T> ReceiveChannel<T>.toSequence(coroutineScope: CoroutineScope = backgroundScope): Sequence<T>

Converts this ReceiveChannel into a (blocking) Sequence, draining the channel from a coroutine launched on coroutineScope. This is what lets ConcurrentSolver implement the synchronous it.unibo.tuprolog.solve.Solver.solve contract in terms of the channel-based ConcurrentSolver.solveConcurrently: elements produced by concurrently running branches of the search tree are funnelled through a queue and replayed, one at a time, to whichever thread iterates the returned Sequence.

actual fun <T> ReceiveChannel<T>.toSequence(coroutineScope: CoroutineScope): Sequence<T>

Converts this ReceiveChannel into a (blocking) Sequence, draining the channel from a coroutine launched on coroutineScope. This is what lets ConcurrentSolver implement the synchronous it.unibo.tuprolog.solve.Solver.solve contract in terms of the channel-based ConcurrentSolver.solveConcurrently: elements produced by concurrently running branches of the search tree are funnelled through a queue and replayed, one at a time, to whichever thread iterates the returned Sequence.

actual fun <T> ReceiveChannel<T>.toSequence(coroutineScope: CoroutineScope): Sequence<T>

Converts this ReceiveChannel into a (blocking) Sequence, draining the channel from a coroutine launched on coroutineScope. This is what lets ConcurrentSolver implement the synchronous it.unibo.tuprolog.solve.Solver.solve contract in terms of the channel-based ConcurrentSolver.solveConcurrently: elements produced by concurrently running branches of the search tree are funnelled through a queue and replayed, one at a time, to whichever thread iterates the returned Sequence.