feat: Floating point arithmetic

This commit is contained in:
Tibo De Peuter 2025-04-15 18:23:04 +02:00
parent f9950a3fd3
commit 4a6850527f
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
13 changed files with 527 additions and 55 deletions

View file

@ -1,12 +1,12 @@
package prolog.logic
import prolog.Answers
import prolog.Substitution
import prolog.Substitutions
import prolog.ast.arithmetic.Expression
import prolog.ast.terms.Integer
import prolog.ast.arithmetic.Integer
import prolog.ast.terms.Term
import prolog.ast.terms.Variable
import prolog.ast.arithmetic.Number
/**
* Low and High are integers, High Low.
@ -78,18 +78,24 @@ fun succ(term1: Expression, term2: Expression, subs: Substitutions): Answers {
* At least two of the three arguments must be instantiated to integers.
*/
fun plus(term1: Expression, term2: Expression, term3: Expression, subs: Substitutions): Answers =
operate(term1, term2, term3, subs, Integer::plus, Integer::minus)
operate(term1, term2, term3, subs, Number::plus, Number::minus)
fun minus(term1: Expression, term2: Expression, term3: Expression, subs: Substitutions): Answers =
operate(term1, term2, term3, subs, Number::minus, Number::plus)
fun mul(term1: Expression, term2: Expression, term3: Expression, subs: Substitutions): Answers =
operate(term1, term2, term3, subs, Integer::times, Integer::div)
operate(term1, term2, term3, subs, Number::times, Number::div)
fun div(term1: Expression, term2: Expression, term3: Expression, subs: Substitutions): Answers =
operate(term1, term2, term3, subs, Number::div, Number::times)
fun operate(
term1: Expression,
term2: Expression,
term3: Expression,
subs: Substitutions,
op: (Integer, Integer) -> Integer,
inverseOp: (Integer, Integer) -> Integer
op: (Number, Number) -> Number,
inverseOp: (Number, Number) -> Number
): Answers = sequence {
val t1 = applySubstitution(term1, subs)
val t2 = applySubstitution(term2, subs)
@ -101,8 +107,8 @@ fun operate(
val e2 = t2.simplify(subs)
val e3 = t3.simplify(subs)
val int3Value = op(e1.to as Integer, e2.to as Integer)
if (int3Value == e3.to as Integer) {
val int3Value = op(e1.to as Number, e2.to as Number)
if (equivalent(int3Value, e3.to, emptyMap())) {
val opSubs: Substitutions = listOfNotNull(e1.mapped, e2.mapped, e3.mapped)
.filter{ pair: Pair<Term, Term>? -> pair != null && !subs.contains(pair.first) }
.toMap()
@ -114,7 +120,7 @@ fun operate(
val e1 = t1.simplify(subs)
val e2 = t2.simplify(subs)
val int3Value = op(e1.to as Integer, e2.to as Integer)
val int3Value = op(e1.to as Number, e2.to as Number)
val int3 = t3 as Variable
yield(Result.success(mapOf(int3 to int3Value) + listOfNotNull(e1.mapped, e2.mapped)))
}
@ -124,7 +130,7 @@ fun operate(
val e = if (nonvariable(t1, subs)) t1.simplify(subs) else t2.simplify(subs)
val e3 = t3.simplify(subs)
val value = inverseOp(e3.to as Integer, e.to as Integer)
val value = inverseOp(e3.to as Number, e.to as Number)
val int = t as Variable
yield(Result.success(mapOf(int to value) + listOfNotNull(e.mapped, e3.mapped)))
}

View file

@ -7,6 +7,9 @@ import prolog.ast.arithmetic.Expression
import prolog.ast.logic.LogicOperator
import prolog.ast.terms.*
import kotlin.NoSuchElementException
import prolog.ast.arithmetic.Number
import prolog.ast.arithmetic.Integer
import prolog.ast.arithmetic.Float
// Apply substitutions to a term
fun applySubstitution(term: Term, subs: Substitutions): Term = when {
@ -101,6 +104,7 @@ fun equivalent(term1: Term, term2: Term, subs: Substitutions): Boolean {
term1 is Atom && term2 is Atom -> compare(term1, term2, subs) == 0
term1 is Structure && term2 is Structure -> compare(term1, term2, subs) == 0
term1 is Integer && term2 is Integer -> compare(term1, term2, subs) == 0
term1 is Number && term2 is Number -> compare(term1, term2, subs) == 0
term1 is Variable && term2 is Variable -> term1 == term2
term1 is Variable -> term1 in subs && equivalent(subs[term1]!!, term2, subs)
term2 is Variable -> term2 in subs && equivalent(subs[term2]!!, term1, subs)
@ -119,16 +123,17 @@ fun compare(term1: Term, term2: Term, subs: Substitutions): Int {
is Variable -> {
when (t2) {
is Variable -> t1.name.compareTo(t2.name)
is Integer -> -1
is Number -> -1
is Atom -> -1
is Structure -> -1
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
}
}
is Integer -> {
is Number -> {
when (t2) {
is Variable -> 1
is Integer -> t1.value.compareTo(t2.value)
is Integer -> (t1.value as Int).compareTo(t2.value)
is Float -> (t1.value as kotlin.Float).compareTo(t2.value)
is Atom -> -1
is Structure -> -1
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
@ -137,7 +142,7 @@ fun compare(term1: Term, term2: Term, subs: Substitutions): Int {
is Atom -> {
when (t2) {
is Variable -> 1
is Integer -> 1
is Number -> 1
is Atom -> t1.name.compareTo(t2.name)
is Structure -> -1
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
@ -146,7 +151,7 @@ fun compare(term1: Term, term2: Term, subs: Substitutions): Int {
is Structure -> {
when (t2) {
is Variable -> 1
is Integer -> 1
is Number -> 1
is Atom -> 1
is Structure -> {
val arityComparison = t1.arguments.size.compareTo(t2.arguments.size)