fix: Satisfy clause

This commit is contained in:
Tibo De Peuter 2025-05-06 14:13:03 +02:00
parent 256a189125
commit 4810b91628
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
3 changed files with 18 additions and 17 deletions

View file

@ -27,30 +27,31 @@ abstract class Clause(var head: Head, var body: Body) : Term, Resolvent {
// Only if the body can be proven, the substitutions should be returned.
// Do this in a lazy way.
val (headEnd, headRenaming) = numbervars(head, Program.variableRenamingStart, subs)
// Since we are only interested in substitutions in the goal (as opposed to the head of this clause),
// we can use variable renaming and filter out the substitutions that are not in the goal.
val (headEnd, headRenaming) = numbervars(head, Program.variableRenamingStart, emptyMap())
Program.variableRenamingStart = headEnd
val renamedHead = applySubstitution(head, subs + headRenaming)
val renamedBody = applySubstitution(body, subs + headRenaming) as Body
unifyLazy(goal, renamedHead, subs).forEach { headAnswer ->
headAnswer.map { headSubs ->
val subsNotInGoal = headSubs.filterNot { occurs(it.key as Variable, goal, emptyMap()) }
renamedBody.satisfy(subsNotInGoal).forEach { bodyAnswer ->
val renamedHead = applySubstitution(head, headRenaming)
val simplifiedGoal = applySubstitution(goal, subs)
unifyLazy(simplifiedGoal, renamedHead, emptyMap()).forEach { headAnswer ->
headAnswer.map { headAndGoalSubs ->
// Filter the substitutions to only include those that map from head to goal
val headToGoalSubs = headAndGoalSubs.filterKeys { it in headRenaming.values }
val goalToHeadSubs = headAndGoalSubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
val newSubs = headRenaming + headToGoalSubs
body.satisfy(newSubs).forEach { bodyAnswer ->
bodyAnswer.fold(
// If the body can be proven, yield the (combined) substitutions
onSuccess = { bodySubs ->
var result = headSubs + bodySubs
result = result
.mapValues { applySubstitution(it.value, result) }
.filterKeys { it !is AnonymousVariable && occurs(it as Variable, goal, emptyMap()) }
// If the body can be proven, yield the (combined) substitutions
var result = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
yield(Result.success(result))
},
onFailure = { error ->
if (error is AppliedCut) {
// Find single solution and return immediately
if (error.subs != null) {
yield(Result.failure(AppliedCut(headSubs + error.subs)))
yield(Result.failure(AppliedCut(headAndGoalSubs + error.subs)))
} else {
yield(Result.failure(AppliedCut()))
}

View file

@ -41,7 +41,7 @@ fun applySubstitution(expr: Expression, subs: Substitutions): Expression = when
}
// Check if a variable occurs in a term
fun occurs(variable: Variable, term: Term, subs: Substitutions): Boolean = when {
fun occurs(variable: Variable, term: Term, subs: Substitutions = emptyMap()): Boolean = when {
variable(term, subs) -> term == variable
atomic(term, subs) -> false
compound(term, subs) -> {