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

commonMain.it.unibo.tuprolog.solve.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.solver

import it.unibo.tuprolog.core.*
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.SideEffect
import it.unibo.tuprolog.solve.TimeInstant
import it.unibo.tuprolog.solve.extractSignature
import it.unibo.tuprolog.solve.primitive.Solve
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.requestIssuingInstant,
    isChoicePointChild: Boolean = false
): Solve.Request = copy(
    newGoal.extractSignature(),
    newGoal.argsList,
    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)
    ),
    requestIssuingInstant = 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 - 2025 Weber Informatics LLC | Privacy Policy