All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.it.unibo.tuprolog.solve.streams.solver.SolverUtils.kt Maven / Gradle / Ivy

Go to download

Experimental, functional-programming-based implementation of Prolog's SLDNF resolution principle

There is a newer version: 1.0.4
Show newest version
/**
 * Utilities to implement Solver resolution behaviour
 *
 * @author Enrico
 */
@file:JvmName("SolverUtils")

package it.unibo.tuprolog.solve.streams.solver

import it.unibo.tuprolog.core.Clause
import it.unibo.tuprolog.core.Directive
import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.core.prepareForExecution
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.TimeInstant
import it.unibo.tuprolog.solve.extractSignature
import it.unibo.tuprolog.solve.primitive.Solve
import it.unibo.tuprolog.solve.sideffects.SideEffect
import kotlin.jvm.JvmName
import kotlin.collections.List as KtList

/** Check whether the receiver term is a well-formed predication */
fun Term.isWellFormed(): Boolean = accept(Clause.bodyWellFormedVisitor)

/**
 * Prepares the receiver Goal for execution
 *
 * For example, the goal `A` is transformed, after preparation for execution, as the Term: `call(A)`
 */
fun Term.prepareForExecutionAsGoal(): Struct =
    // exploits "Clause" implementation of prepareForExecution() to do that
    Directive.of(this).prepareForExecution().args.single().castTo()

/** Computes the ordered selection of elements, lazily, according to provided selection strategy */
fun  Sequence.orderWithStrategy(
    context: ExecutionContext,
    selectionStrategy: (Sequence, ExecutionContext) -> E,
): Sequence =
    when (any()) {
        true ->
            sequence {
                selectionStrategy(this@orderWithStrategy, context).let { selected ->
                    yield(selected)
                    yieldAll(
                        filterIndexed { index, _ -> index != indexOf(selected) }
                            .orderWithStrategy(context, selectionStrategy),
                    )
                }
            }
        else -> emptySequence()
    }

/** Checks if this sequence of elements holds more than one element, lazily */
fun moreThanOne(elements: Sequence<*>): Boolean =
    with(elements.iterator()) {
        when {
            !hasNext() -> false // no element
            else -> {
                next()
                hasNext() // more elements, if first element has a next element
            }
        }
    }

/**
 * A method to create a new [Solve.Request] physically chained to receiver request.
 *
 * @param newGoal The new solve request goal
 * @param toPropagateContextData The context data to be propagated to the new request
 * @param toAddSubstitutions The added substitutions to new request context, if any
 * @param baseSideEffectManager The base side effect manager to be injected in the new solve request, if different from physical parent request one
 * @param requestIssuingInstant The current time instant on new request creation, if different from method invocation time instant
 * @param isChoicePointChild Whether this new request is considered a child of a Choice Point
 */
internal fun Solve.Request.newSolveRequest(
    newGoal: Struct,
    toAddSubstitutions: Substitution = Substitution.empty(),
    toPropagateContextData: ExecutionContext = context,
    baseSideEffectManager: SideEffectManagerImpl = context.sideEffectManager,
    requestIssuingInstant: TimeInstant = this.startTime,
    isChoicePointChild: Boolean = false,
): Solve.Request =
    copy(
        newGoal.extractSignature(),
        newGoal.args,
        context.copy(
            libraries = toPropagateContextData.libraries,
            flags = toPropagateContextData.flags,
            staticKb = toPropagateContextData.staticKb,
            dynamicKb = toPropagateContextData.dynamicKb,
            inputChannels = toPropagateContextData.inputChannels,
            outputChannels = toPropagateContextData.outputChannels,
            substitution = (context.substitution + toAddSubstitutions) as Substitution.Unifier,
            sideEffectManager = baseSideEffectManager.creatingNewRequest(context, isChoicePointChild, this),
        ),
        startTime = requestIssuingInstant,
    )

/** Responds to this solve request forwarding the provided [otherResponse] data */
fun Solve.Request.replyWith(otherResponse: Solve.Response): Solve.Response =
    with(otherResponse) {
        replyWith(
            solution,
            sideEffectManager ?: [email protected](),
            *sideEffects.toTypedArray(),
        )
    }

/** Utility function to add side effects without duplicating them */
fun KtList.addWithNoDuplicates(toAddSideEffects: KtList): KtList {
    var duplicatedCount = 0
    forEach { sideEffect ->
        if (toAddSideEffects.find { toAddSideEffect -> sideEffect === toAddSideEffect } !== null) {
            duplicatedCount++
        }
    }
    return this + toAddSideEffects.drop(duplicatedCount)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy