refactor: Rework

This commit is contained in:
Tibo De Peuter 2025-04-15 12:32:59 +02:00
parent ac55ed4c64
commit 6469dd6ced
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
34 changed files with 593 additions and 552 deletions

View file

@ -1,10 +1,11 @@
package prolog.builtins
import prolog.Answers
import prolog.Substitutions
import prolog.ast.arithmetic.ArithmeticOperator
import prolog.ast.arithmetic.Expression
import prolog.ast.logic.LogicOperand
import prolog.ast.logic.LogicOperator
import prolog.ast.logic.Provable
import prolog.ast.arithmetic.Simplification
import prolog.ast.logic.Satisfiable
import prolog.ast.terms.*
import prolog.logic.*
@ -20,20 +21,20 @@ import prolog.logic.*
* True if expression Expr1 evaluates to a number non-equal to Expr2.
*/
class EvaluatesToDifferent(private val left: Expression, private val right: Expression) :
ArithmeticOperator(Atom("=\\="), left, right) {
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
val t1 = left.evaluate(subs)
val t2 = right.evaluate(subs)
Operator(Atom("=\\="), left, right), Satisfiable {
override fun satisfy(subs: Substitutions): Answers {
val t1 = left.simplify(subs)
val t2 = right.simplify(subs)
// Should both be instantiated
if (!atomic(t1.first) || !atomic(t2.first)) {
throw IllegalArgumentException("Both operands must be instantiated")
if (!atomic(t1.to, subs) || !atomic(t2.to, subs)) {
return sequenceOf(Result.failure(IllegalArgumentException("Both operands must be instantiated")))
}
return if (equivalent(t1.first, t2.first)) {
Pair(False, emptyMap())
return if (equivalent(t1.to, t2.to, subs)) {
emptySequence()
} else {
Pair(True, t1.second + t2.second)
sequenceOf(Result.success(emptyMap()))
}
}
@ -43,21 +44,17 @@ class EvaluatesToDifferent(private val left: Expression, private val right: Expr
* True if Expr1 evaluates to a number equal to Expr2.
*/
class EvaluatesTo(private val left: Expression, private val right: Expression) :
ArithmeticOperator(Atom("=:="), left, right) {
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
val t1 = left.evaluate(subs)
val t2 = right.evaluate(subs)
Operator(Atom("=:="), left, right) {
override fun satisfy(subs: Substitutions): Answers {
val t1 = left.simplify(subs)
val t2 = right.simplify(subs)
// Should both be instantiated
if (!atomic(t1.first) || !atomic(t2.first)) {
throw IllegalArgumentException("Both operands must be instantiated")
if (!atomic(t1.to, subs) || !atomic(t2.to, subs)) {
return sequenceOf(Result.failure(IllegalArgumentException("Both operands must be instantiated")))
}
return if (equivalent(t1.first, t2.first)) {
Pair(True, t1.second + t2.second)
} else {
Pair(False, emptyMap())
}
return if (equivalent(t1.to, t2.to, subs)) sequenceOf(Result.success(emptyMap())) else emptySequence()
}
}
@ -65,16 +62,20 @@ class EvaluatesTo(private val left: Expression, private val right: Expression) :
* True when Number is the value to which Expr evaluates.
*/
class Is(private val left: Expression, private val right: Expression) :
Operator(Atom("is"), left, right), Provable {
override fun prove(subs: Substituted): Sequence<Substituted> {
val t1 = left.evaluate(subs)
val t2 = right.evaluate(subs)
Operator(Atom("is"), left, right), Satisfiable {
override fun satisfy(subs: Substitutions): Answers {
val t1 = left.simplify(subs)
val t2 = right.simplify(subs)
if (!atomic(t2.first)) {
throw IllegalArgumentException("Arguments are not sufficiently instantiated")
if (!atomic(t2.to, subs)) {
return sequenceOf(Result.failure(IllegalArgumentException("Right operand must be instantiated")))
}
return unifyLazy(t1.first, t2.first, subs).map{ it + t1.second + t2.second }
if (!variable(t1.to, subs) && equivalent(t1.to, t2.to, subs + listOfNotNull(t1.mapped, t2.mapped))) {
return sequenceOf(Result.success(emptyMap()))
}
return unifyLazy(t1.to, t2.to, subs)
}
}
@ -93,10 +94,11 @@ class Positive(operand: Expression) : Add(Integer(0), operand)
*/
open class Add(private val expr1: Expression, private val expr2: Expression) :
ArithmeticOperator(Atom("+"), expr1, expr2) {
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
override fun simplify(subs: Substitutions): Simplification {
val result = Variable("Result")
val map = plus(expr1, expr2, result, subs)
return result.evaluate(map.first().getOrThrow())
val simplification = result.simplify(map.first().getOrThrow())
return Simplification(this, simplification.to)
}
}
@ -105,10 +107,11 @@ open class Add(private val expr1: Expression, private val expr2: Expression) :
*/
open class Subtract(private val expr1: Expression, private val expr2: Expression) :
ArithmeticOperator(Atom("-"), expr1, expr2) {
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
override fun simplify(subs: Substitutions): Simplification {
val result = Variable("Result")
val map = plus(expr2, result, expr1, subs)
return result.evaluate(map.first().getOrThrow())
val simplification = result.simplify(map.first().getOrThrow())
return Simplification(this, simplification.to)
}
}
@ -118,10 +121,11 @@ open class Subtract(private val expr1: Expression, private val expr2: Expression
*/
class Multiply(private val expr1: Expression, private val expr2: Expression) :
ArithmeticOperator(Atom("*"), expr1, expr2) {
override fun evaluate(subs: Substituted): Pair<Term, Substituted> {
override fun simplify(subs: Substitutions): Simplification {
val result = Variable("Result")
val map = mul(expr1, expr2, result, subs)
return result.evaluate(map.first().getOrThrow())
val simplification = result.simplify(map.first().getOrThrow())
return Simplification(this, simplification.to)
}
}
@ -133,20 +137,24 @@ class Multiply(private val expr1: Expression, private val expr2: Expression) :
class Between(private val expr1: Expression, private val expr2: Expression, private val expr3: Expression) :
Operator(Atom("between"), expr1, expr2) {
override fun prove(subs: Substituted): Sequence<Substituted> {
val e1 = expr1.evaluate(subs)
val e2 = expr2.evaluate(subs)
val e3 = expr3.evaluate(subs)
override fun satisfy(subs: Substitutions): Answers {
val e1 = expr1.simplify(subs)
val e2 = expr2.simplify(subs)
val e3 = expr3.simplify(subs)
require(e1.first is Integer && e2.first is Integer) { "Arguments must be integers" }
require(e1.to is Integer && e2.to is Integer) { "Arguments must be integers" }
val v1 = e1.first as Integer
val v2 = e2.first as Integer
val v1 = e1.to as Integer
val v2 = e2.to as Integer
return if (variable(e3.first)) {
between(v1, v2, e3.first as Variable).map { it + e1.second + e2.second }
return if (variable(e3.to, subs)) {
between(v1, v2, e3.to as Variable).map { answer ->
answer.mapCatching { it + listOfNotNull(e1.mapped, e2.mapped) }
}
} else {
between(v1, v2, e3.first as Integer).map { it + e1.second + e2.second }
between(v1, v2, e3.to as Integer).map { answer ->
answer.mapCatching { it + listOfNotNull(e1.mapped, e2.mapped) }
}
}
}
}