fix: Satisfy clause
This commit is contained in:
parent
256a189125
commit
4810b91628
3 changed files with 18 additions and 17 deletions
|
@ -4,6 +4,6 @@ leq(s(X), s(Y)) :- leq(X, Y).
|
|||
:- initialization(main).
|
||||
|
||||
main :-
|
||||
leq(X, s(s(s(0)))),
|
||||
write(X), nl,
|
||||
leq(A, s(s(s(0)))),
|
||||
write(A), nl,
|
||||
fail.
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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) -> {
|
||||
|
|
Reference in a new issue