This repository has been archived on 2025-09-23. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
2025LogProg-project-GhentPr.../src/prolog/unify.kt
2025-04-05 17:36:37 +02:00

83 lines
2.8 KiB
Kotlin

package prolog
import prolog.builtins.atomic
import prolog.builtins.compound
import prolog.builtins.variable
import prolog.components.Goal
import prolog.components.terms.Term
import prolog.components.terms.Variable
import prolog.components.terms.Structure
import java.util.*
typealias Substitution = Map<Variable, Term>
// Apply substitutions to a term
fun applySubstitution(term: Term, substitution: Substitution): Term = when {
variable(term) -> (term as Variable).alias().map { applySubstitution(it, substitution) }.orElse(term)
atomic(term) -> term
compound(term) -> {
val structure = term as Structure
Structure(structure.name, structure.arguments.map { applySubstitution(it, substitution) })
}
else -> term
}
// Check if a variable occurs in a term
fun occurs(variable: Variable, term: Term): Boolean = when {
variable(term) -> term == variable
atomic(term) -> false
compound(term) -> {
val structure = term as Structure
structure.arguments.any { occurs(variable, it) }
}
else -> false
}
// Generate possible substitutions
fun generateSubstitutions(term1: Term, term2: Term, substitution: Substitution): Sequence<Substitution> = sequence {
val t1 = applySubstitution(term1, substitution)
val t2 = applySubstitution(term2, substitution)
when {
t1 == t2 -> yield(substitution)
variable(t1) -> {
val variable = t1 as Variable
if (!occurs(variable, t2)) {
variable.bind(t2)
yield(substitution + (variable to t2))
}
}
variable(t2) -> {
val variable = t2 as Variable
if (!occurs(variable, t1)) {
variable.bind(t1)
yield(substitution + (variable to t1))
}
}
compound(t1) && compound(t2) -> {
val structure1 = t1 as Structure
val structure2 = t2 as Structure
if (structure1.functor == structure2.functor) {
val newSubstitution = structure1.arguments.zip(structure2.arguments).fold(substitution) { acc, (arg1, arg2) ->
generateSubstitutions(arg1, arg2, acc).firstOrNull() ?: return@sequence
}
yield(newSubstitution)
}
}
else -> {}
}
}
// Unify two terms with backtracking and lazy evaluation
fun unifyLazy(term1: Term, term2: Term, substitution: Substitution = emptyMap()): Sequence<Substitution> {
return generateSubstitutions(term1, term2, substitution)
}
fun unify(term1: Term, term2: Term): Optional<Substitution> {
val substitutions = unifyLazy(term1, term2).toList()
return if (substitutions.isEmpty()) {
Optional.empty()
} else {
Optional.of(substitutions.first())
}
}