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

commonMain.it.unibo.tuprolog.unify.AbstractUnificator.kt Maven / Gradle / Ivy

package it.unibo.tuprolog.unify

import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Substitution.Companion.empty
import it.unibo.tuprolog.core.Substitution.Companion.failed
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.core.Var
import it.unibo.tuprolog.unify.Equation.Assignment
import it.unibo.tuprolog.unify.Equation.Comparison
import it.unibo.tuprolog.unify.Equation.Contradiction
import it.unibo.tuprolog.unify.Equation.Identity
import it.unibo.tuprolog.utils.dequeOf
import kotlin.jvm.JvmOverloads

abstract class AbstractUnificator @JvmOverloads constructor(override val context: Substitution = empty()) : Unificator {

    /** The context converted to equivalent equations */
    private val contextEquations: Iterable> by lazy { context.toEquations() }

    /** Checks provided [Term]s for equality */
    protected abstract fun checkTermsEquality(first: Term, second: Term): Boolean

    /** Implements the so called occur-check; checks if the [variable] is present in [term] */
    private fun occurrenceCheck(variable: Var, term: Term): Boolean =
        when (term) {
            is Var -> checkTermsEquality(variable, term)
            is Struct -> term.variables.any { occurrenceCheck(variable, it) }
            else -> false
        }

    /** Returns the sequence of equations resulting from the comparison of given [Term]s */
    private fun equationsFor(term1: Term, term2: Term): Sequence> =
        Equation.allOf(term1, term2, this::checkTermsEquality)

    private fun equationsFor(substitution1: Substitution, substitution2: Substitution): Sequence> =
        Equation.from(
            (substitution1.asSequence() + substitution2.asSequence()).map { it.toPair() }
        )

    /** A function to apply given [substitution] to [equations], skipping the equation at given [exceptIndex] */
    private fun applySubstitutionToEquations(
        substitution: Substitution,
        equations: MutableList>,
        exceptIndex: Int
    ): Boolean {
        var changed = false

        for (i in equations.indices) {
            if (i == exceptIndex || equations[i] is Contradiction || equations[i] is Identity) continue

            val currentEq = equations[i]
            val (newLhs, newRhs) = currentEq.apply(substitution).toPair()

            if (currentEq.lhs != newLhs || currentEq.rhs != newRhs) {
                equations[i] = Equation.of(newLhs, newRhs, this::checkTermsEquality)
                changed = true
            }
        }

        return changed
    }

    private fun mgu(equations: MutableList>, occurCheckEnabled: Boolean): Substitution {
        var changed = true

        while (changed) {
            changed = false
            val eqIterator = equations.listIterator()

            while (eqIterator.hasNext()) {
                when (val eq = eqIterator.next()) {
                    is Contradiction -> {
                        return failed()
                    }
                    is Identity -> {
                        eqIterator.remove()
                        changed = true
                    }
                    is Assignment -> {
                        if (occurCheckEnabled && occurrenceCheck(eq.lhs as Var, eq.rhs)) {
                            return failed()
                        } else {
                            changed = changed || applySubstitutionToEquations(
                                Substitution.of(eq.lhs as Var, eq.rhs),
                                equations,
                                eqIterator.previousIndex()
                            )
                        }
                    }
                    is Comparison -> {
                        eqIterator.remove()
                        insertion@ for (it in equationsFor(eq.lhs, eq.rhs)) {
                            when (it) {
                                is Identity -> continue@insertion
                                is Contradiction -> return failed()
                                else -> eqIterator.add(it)
                            }
                        }
                        changed = true
                    }
                }
            }
        }

        return equations.filterIsInstance>().toSubstitution()
    }

    override fun mgu(term1: Term, term2: Term, occurCheckEnabled: Boolean): Substitution {
        if (context.isFailed) return failed()
        val equations = dequeOf(contextEquations + equationsFor(term1, term2))
        return mgu(equations, occurCheckEnabled)
    }

    override fun merge(
        substitution1: Substitution,
        substitution2: Substitution,
        occurCheckEnabled: Boolean
    ): Substitution {
        if (context.isFailed) return failed()

        val equations = dequeOf(contextEquations + equationsFor(substitution1, substitution2))
        return mgu(equations, occurCheckEnabled)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy