fix: Fixes
This commit is contained in:
parent
a1187238c3
commit
83f65bd683
8 changed files with 65 additions and 29 deletions
|
@ -3,8 +3,9 @@ package prolog.ast.arithmetic
|
|||
import prolog.Answers
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.logic.LogicOperand
|
||||
import prolog.ast.terms.Body
|
||||
|
||||
data class Integer(override val value: Int) : Number, LogicOperand() {
|
||||
data class Integer(override val value: Int) : Number, Body, LogicOperand() {
|
||||
// Integers are already evaluated
|
||||
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import prolog.ast.Database.Program
|
|||
import prolog.ast.terms.*
|
||||
import prolog.builtins.True
|
||||
import prolog.flags.AppliedCut
|
||||
import prolog.flags.AppliedShift
|
||||
import prolog.logic.applySubstitution
|
||||
import prolog.logic.numbervars
|
||||
import prolog.logic.occurs
|
||||
|
@ -27,18 +28,23 @@ 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 simplifiedGoal = applySubstitution(goal, 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 (goalEnd, goalRenaming) = numbervars(simplifiedGoal, headEnd, emptyMap())
|
||||
Program.variableRenamingStart = goalEnd
|
||||
|
||||
val reverseGoalRenaming = goalRenaming.entries.associate { (key, value) -> value to key }
|
||||
|
||||
val renamedHead = applySubstitution(head, headRenaming)
|
||||
val simplifiedGoal = applySubstitution(goal, subs)
|
||||
unifyLazy(simplifiedGoal, renamedHead, emptyMap()).forEach { headAnswer ->
|
||||
val renamedGoal = applySubstitution(simplifiedGoal, goalRenaming)
|
||||
unifyLazy(renamedGoal, 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 goalToHeadSubs = headAndGoalSubs.filterKeys { occurs(it as Variable, renamedGoal) }
|
||||
val headResult = headToGoalSubs.filterKeys { key ->
|
||||
goalToHeadSubs.any { occurs(key as Variable, it.value) }
|
||||
}
|
||||
|
@ -47,24 +53,34 @@ abstract class Clause(var head: Head, var body: Body) : Term, Resolvent {
|
|||
bodyAnswer.fold(
|
||||
onSuccess = { bodySubs ->
|
||||
// If the body can be proven, yield the (combined) substitutions
|
||||
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
||||
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
|
||||
val renamedGoalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
||||
val goalResult =
|
||||
renamedGoalResult.mapKeys { applySubstitution(it.key, reverseGoalRenaming) }
|
||||
val renamedBodyResult = bodySubs.filterKeys { occurs(it as Variable, renamedGoal) }
|
||||
val bodyResult = renamedBodyResult.mapKeys { applySubstitution(it.key, reverseGoalRenaming) }
|
||||
yield(Result.success(goalResult + headResult + bodyResult))
|
||||
},
|
||||
onFailure = { error ->
|
||||
if (error is AppliedCut) {
|
||||
// Find single solution and return immediately
|
||||
if (error.subs != null) {
|
||||
val bodySubs = error.subs
|
||||
val goalResult = goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
||||
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, simplifiedGoal) }
|
||||
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
|
||||
} else {
|
||||
yield(Result.failure(AppliedCut()))
|
||||
when (error) {
|
||||
is AppliedCut -> {
|
||||
// Find single solution and return immediately
|
||||
if (error.subs != null) {
|
||||
val bodySubs = error.subs
|
||||
val goalResult =
|
||||
goalToHeadSubs.mapValues { applySubstitution(it.value, bodySubs) }
|
||||
val bodyResult = bodySubs.filterKeys { occurs(it as Variable, renamedGoal) }
|
||||
yield(Result.failure(AppliedCut(goalResult + headResult + bodyResult)))
|
||||
} else {
|
||||
yield(Result.failure(AppliedCut()))
|
||||
}
|
||||
return@sequence
|
||||
}
|
||||
return@sequence
|
||||
} else {
|
||||
yield(Result.failure(error))
|
||||
|
||||
is AppliedShift -> {
|
||||
yield(Result.failure(error))
|
||||
}
|
||||
|
||||
else -> yield(Result.failure(error))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package prolog.ast.terms
|
||||
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.logic.Satisfiable
|
||||
|
||||
interface Body : Term, Satisfiable
|
||||
interface Body : Term, Satisfiable {
|
||||
override fun applySubstitution(subs: Substitutions): Body
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
|
|||
right.fold(
|
||||
// If the right part succeeds, yield the result with the left substitutions
|
||||
onSuccess = { rightSubs ->
|
||||
yield(Result.success(leftSubs + rightSubs))
|
||||
yield(Result.success(rightSubs + leftSubs))
|
||||
},
|
||||
onFailure = { exception ->
|
||||
// If the right part fails, check if it's a cut
|
||||
|
@ -74,8 +74,8 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
|
|||
}
|
||||
|
||||
fun findNextCutSolution(appliedCut: AppliedCut): Answers = sequence {
|
||||
val leftSubs = appliedCut.subs
|
||||
right.satisfy(subs + (appliedCut.subs!!)).firstOrNull()?.map { rightSubs ->
|
||||
val leftSubs = appliedCut.subs ?: emptyMap()
|
||||
right.satisfy(subs + leftSubs).firstOrNull()?.map { rightSubs ->
|
||||
// If the right part succeeds, yield the result with the left substitutions
|
||||
yield(Result.success(leftSubs + rightSubs))
|
||||
return@sequence
|
||||
|
|
|
@ -39,7 +39,7 @@ class Reset(private val goal: Goal, private val ball: Term, private val cont: Te
|
|||
if (failure is AppliedShift) {
|
||||
require(failure.cont != null) { "Shift must have a continuation" }
|
||||
// Reset/3 succeeds immediately, binding Term1 to Term2 and Cont to the remainder of Goal.
|
||||
val shiftSubs = failure.subs
|
||||
val shiftSubs = failure.subs + subs
|
||||
val appliedBall = applySubstitution(failure.ball, shiftSubs)
|
||||
val appliedCont = applySubstitution(failure.cont, shiftSubs)
|
||||
Conjunction(Unify(ball, appliedBall), Unify(appliedCont, cont))
|
||||
|
|
Reference in a new issue