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

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

There is a newer version: 0.17.4
Show newest version
package it.unibo.tuprolog.unify

import it.unibo.tuprolog.core.Atom
import it.unibo.tuprolog.core.Cons
import it.unibo.tuprolog.core.Constant
import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.core.ToTermConvertible
import it.unibo.tuprolog.core.Tuple
import it.unibo.tuprolog.core.Var
import kotlin.js.JsName
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
import it.unibo.tuprolog.core.List as LogicList

/**
 * A class representing an Equation of logic terms, to be unified;
 *
 * LHS stands for Left-Hand side and RHS stands for Right-Hand side, of the Equation
 */
sealed class Equation(
    /** The left-hand side of the equation */
    @JsName("lhs") open val lhs: A,
    /** The right-hand side of the equation */
    @JsName("rhs") open val rhs: B
) : ToTermConvertible {

    /** An equation of identical [Term]s */
    data class Identity(override val lhs: T, override val rhs: T) : Equation(lhs, rhs)

    /** An equation stating [Var] = [Term] */
    data class Assignment(override val lhs: A, override val rhs: B) :
        Equation(lhs, rhs)

    /** An equation comparing [Term]s, possibly different */
    data class Comparison(override val lhs: A, override val rhs: B) :
        Equation(lhs, rhs)

    /** A contradicting equation, trying to equate non equal [Term]s */
    data class Contradiction(override val lhs: A, override val rhs: B) :
        Equation(lhs, rhs)

    override fun toTerm(): Struct = Struct.of("=", lhs, rhs)

    @JsName("toPair")
    fun toPair(): Pair = Pair(lhs, rhs)

    @JsName("swap")
    fun swap(): Equation = of(rhs, lhs)

    /**
     * Applies given [substitution] to the Equation left-hand and right-hand sides, returning the new Equation
     *
     * To modify default equality between [Term]s, a custom [equalityChecker] can be provided
     */
    @JvmOverloads
    @JsName("apply")
    fun apply(
        substitution: Substitution,
        equalityChecker: (Term, Term) -> Boolean = Term::equals
    ): Equation =
        of(lhs[substitution], rhs[substitution], equalityChecker)

    /** Equation companion object */
    companion object {

        /** Creates an Equation with provided left-hand and right-hand sides */
        @JvmStatic
        @JvmOverloads
        @JsName("of")
        fun  of(
            lhs: A,
            rhs: B,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Equation =
            when {
                lhs is Var && rhs is Var -> if (equalityChecker(lhs, rhs)) Identity(lhs, rhs) else Assignment(lhs, rhs)
                lhs is Var -> Assignment(lhs, rhs)
                rhs is Var -> Assignment(rhs, lhs)
                lhs is Constant && rhs is Constant ->
                    if (equalityChecker(lhs, rhs)) Identity(lhs, rhs)
                    else Contradiction(lhs, rhs)
                lhs is Constant || rhs is Constant -> Contradiction(lhs, rhs)
                lhs is Struct && rhs is Struct && (lhs.arity != rhs.arity || lhs.functor != rhs.functor) ->
                    Contradiction(lhs, rhs)
                else -> Comparison(lhs, rhs)
            }

        /** Creates an Equation from given [Pair] */
        @JvmStatic
        @JvmOverloads
        @JsName("ofPair")
        fun  of(
            pair: Pair,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Equation =
            of(pair.first, pair.second, equalityChecker)

        @JvmStatic
        @JvmOverloads
        @JsName("fromSequence")
        fun  from(
            pairs: Sequence>,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> =
            pairs.flatMap { allOf(it, equalityChecker) }

        @JvmStatic
        @JvmOverloads
        @JsName("fromIterable")
        fun  from(
            pairs: Iterable>,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> = from(pairs.asSequence(), equalityChecker)

        @JvmStatic
        @JvmOverloads
        @JsName("from")
        fun  from(
            vararg pairs: Pair,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> = from(sequenceOf(*pairs), equalityChecker)

        /** Creates all equations resulting from the deep inspection of given [Pair] of [Term]s */
        @JvmStatic
        @JvmOverloads
        @JsName("allOfPair")
        fun  allOf(
            pair: Pair,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> =
            allOf(pair.first, pair.second, equalityChecker)

        private fun allOfLists(
            lhs: LogicList,
            rhs: LogicList,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> {
            return lhs.unfold().zip(rhs.unfold()).flatMap { (l, r) ->
                when {
                    l is Cons && r is Cons -> sequenceOf(of(l.head, r.head, equalityChecker))
                    l is LogicList && r is LogicList -> sequenceOf(of(l, r, equalityChecker))
                    else -> allOf(l, r, equalityChecker)
                }
            }
        }

        private fun allOfTuples(
            lhs: Tuple,
            rhs: Tuple,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> {
            return lhs.unfold().zip(rhs.unfold()).flatMap { (l, r) ->
                when {
                    l is Tuple && r is Tuple -> sequenceOf(of(l.left, r.left, equalityChecker))
                    else -> allOf(l, r, equalityChecker)
                }
            }
        }

        /** Creates all equations resulting from the deep inspection of provided left-hand and right-hand sides' [Term] */
        @JvmStatic
        @JvmOverloads
        @JsName("allOf")
        fun  allOf(
            lhs: A,
            rhs: B,
            equalityChecker: (Term, Term) -> Boolean = Term::equals
        ): Sequence> =
            when {
                (lhs is Atom && rhs is Atom) -> {
                    sequenceOf(of(lhs, rhs, equalityChecker))
                }
                lhs is LogicList && rhs is LogicList -> {
                    allOfLists(lhs, rhs, equalityChecker)
                }
                lhs is Tuple && rhs is Tuple -> {
                    allOfTuples(lhs, rhs, equalityChecker)
                }
                lhs is Struct && rhs is Struct && lhs.arity == rhs.arity && lhs.functor == rhs.functor -> {
                    lhs.argsSequence.zip(rhs.argsSequence).flatMap { allOf(it, equalityChecker) }
                }
                else -> {
                    sequenceOf(of(lhs, rhs, equalityChecker))
                }
            }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy