feat: Floating point arithmetic
This commit is contained in:
parent
f9950a3fd3
commit
4a6850527f
13 changed files with 527 additions and 55 deletions
34
src/prolog/ast/arithmetic/Float.kt
Normal file
34
src/prolog/ast/arithmetic/Float.kt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package prolog.ast.arithmetic
|
||||||
|
|
||||||
|
import prolog.Substitutions
|
||||||
|
|
||||||
|
class Float(override val value: kotlin.Float): Number {
|
||||||
|
// Floats are already evaluated
|
||||||
|
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
||||||
|
|
||||||
|
override fun toString(): String = value.toString()
|
||||||
|
|
||||||
|
override operator fun plus(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value + other.value)
|
||||||
|
is Integer -> Float(value + other.value.toFloat())
|
||||||
|
else -> throw IllegalArgumentException("Cannot add $this and $other")
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun minus(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value - other.value)
|
||||||
|
is Integer -> Float(value - other.value.toFloat())
|
||||||
|
else -> throw IllegalArgumentException("Cannot subtract $this and $other")
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun div(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value / other.value)
|
||||||
|
is Integer -> Float(value / other.value.toFloat())
|
||||||
|
else -> throw IllegalArgumentException("Cannot divide $this and $other")
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun times(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value * other.value)
|
||||||
|
is Integer -> Float(value * other.value.toFloat())
|
||||||
|
else -> throw IllegalArgumentException("Cannot multiply $this and $other")
|
||||||
|
}
|
||||||
|
}
|
40
src/prolog/ast/arithmetic/Integer.kt
Normal file
40
src/prolog/ast/arithmetic/Integer.kt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package prolog.ast.arithmetic
|
||||||
|
|
||||||
|
import prolog.Substitutions
|
||||||
|
|
||||||
|
data class Integer(override val value: Int) : Number {
|
||||||
|
// Integers are already evaluated
|
||||||
|
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
||||||
|
|
||||||
|
override fun toString(): String = value.toString()
|
||||||
|
|
||||||
|
override operator fun plus(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value + other.value)
|
||||||
|
is Integer -> Integer(value + other.value)
|
||||||
|
else -> throw IllegalArgumentException("Cannot add $this and $other")
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun minus(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value - other.value)
|
||||||
|
is Integer -> Integer(value - other.value)
|
||||||
|
else -> throw IllegalArgumentException("Cannot subtract $this and $other")
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun div(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value / other.value)
|
||||||
|
is Integer -> {
|
||||||
|
if (value / other.value * other.value == value) {
|
||||||
|
Integer(value / other.value)
|
||||||
|
} else {
|
||||||
|
Float(value / other.value.toFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Cannot divide $this and $other")
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun times(other: Number): Number = when (other) {
|
||||||
|
is Float -> Float(value * other.value)
|
||||||
|
is Integer -> Integer(value * other.value)
|
||||||
|
else -> throw IllegalArgumentException("Cannot multiply $this and $other")
|
||||||
|
}
|
||||||
|
}
|
10
src/prolog/ast/arithmetic/Number.kt
Normal file
10
src/prolog/ast/arithmetic/Number.kt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package prolog.ast.arithmetic
|
||||||
|
|
||||||
|
interface Number: Expression {
|
||||||
|
val value: kotlin.Number
|
||||||
|
|
||||||
|
fun plus(other: Number): Number
|
||||||
|
fun minus(other: Number): Number
|
||||||
|
fun times(other: Number): Number
|
||||||
|
fun div(other: Number): Number
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
package prolog.ast.terms
|
|
||||||
|
|
||||||
import prolog.Substitutions
|
|
||||||
import prolog.ast.arithmetic.Expression
|
|
||||||
import prolog.ast.arithmetic.Simplification
|
|
||||||
|
|
||||||
data class Integer(val value: Int): Expression {
|
|
||||||
// Integers are already evaluated
|
|
||||||
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return value.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun plus(other: Integer): Integer {
|
|
||||||
return Integer(value + other.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun minus(other: Integer): Integer {
|
|
||||||
return Integer(value - other.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun times(other: Integer): Integer {
|
|
||||||
return Integer(value * other.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun div(other: Integer): Integer {
|
|
||||||
return Integer(value / other.value)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,8 +5,9 @@ import prolog.logic.compare
|
||||||
/**
|
/**
|
||||||
* Value in Prolog.
|
* Value in Prolog.
|
||||||
*
|
*
|
||||||
* A [Term] is either a [Variable], [Atom], [Integer], float or [CompoundTerm].
|
* A [Term] is either a [Variable], [Atom], [Integer][prolog.ast.arithmetic.Integer],
|
||||||
* In addition, SWI-Prolog also defines the type string.
|
* [Float][prolog.ast.arithmetic.Float] or [CompoundTerm].
|
||||||
|
* In addition, SWI-Prolog also defines the type TODO string.
|
||||||
*/
|
*/
|
||||||
interface Term : Comparable<Term> {
|
interface Term : Comparable<Term> {
|
||||||
override fun compareTo(other: Term): Int = compare(this, other, emptyMap())
|
override fun compareTo(other: Term): Int = compare(this, other, emptyMap())
|
||||||
|
|
|
@ -4,6 +4,7 @@ import prolog.Answers
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.arithmetic.ArithmeticOperator
|
import prolog.ast.arithmetic.ArithmeticOperator
|
||||||
import prolog.ast.arithmetic.Expression
|
import prolog.ast.arithmetic.Expression
|
||||||
|
import prolog.ast.arithmetic.Integer
|
||||||
import prolog.ast.arithmetic.Simplification
|
import prolog.ast.arithmetic.Simplification
|
||||||
import prolog.ast.logic.Satisfiable
|
import prolog.ast.logic.Satisfiable
|
||||||
import prolog.ast.terms.*
|
import prolog.ast.terms.*
|
||||||
|
@ -115,7 +116,6 @@ open class Subtract(private val expr1: Expression, private val expr2: Expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Expr * Expr
|
|
||||||
/**
|
/**
|
||||||
* Result = Expr1 * Expr2
|
* Result = Expr1 * Expr2
|
||||||
*/
|
*/
|
||||||
|
@ -129,7 +129,15 @@ class Multiply(private val expr1: Expression, private val expr2: Expression) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Expr / Expr
|
class Divide(private val expr1: Expression, private val expr2: Expression) :
|
||||||
|
ArithmeticOperator(Atom("/"), expr1, expr2) {
|
||||||
|
override fun simplify(subs: Substitutions): Simplification {
|
||||||
|
val result = Variable("Result")
|
||||||
|
val map = div(expr1, expr2, result, subs)
|
||||||
|
val simplification = result.simplify(map.first().getOrThrow())
|
||||||
|
return Simplification(this, simplification.to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Expr mod Expr
|
// TODO Expr mod Expr
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package prolog.logic
|
package prolog.logic
|
||||||
|
|
||||||
import prolog.Answers
|
import prolog.Answers
|
||||||
import prolog.Substitution
|
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.arithmetic.Expression
|
import prolog.ast.arithmetic.Expression
|
||||||
import prolog.ast.terms.Integer
|
import prolog.ast.arithmetic.Integer
|
||||||
import prolog.ast.terms.Term
|
import prolog.ast.terms.Term
|
||||||
import prolog.ast.terms.Variable
|
import prolog.ast.terms.Variable
|
||||||
|
import prolog.ast.arithmetic.Number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Low and High are integers, High ≥Low.
|
* 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.
|
* At least two of the three arguments must be instantiated to integers.
|
||||||
*/
|
*/
|
||||||
fun plus(term1: Expression, term2: Expression, term3: Expression, subs: Substitutions): Answers =
|
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 =
|
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(
|
fun operate(
|
||||||
term1: Expression,
|
term1: Expression,
|
||||||
term2: Expression,
|
term2: Expression,
|
||||||
term3: Expression,
|
term3: Expression,
|
||||||
subs: Substitutions,
|
subs: Substitutions,
|
||||||
op: (Integer, Integer) -> Integer,
|
op: (Number, Number) -> Number,
|
||||||
inverseOp: (Integer, Integer) -> Integer
|
inverseOp: (Number, Number) -> Number
|
||||||
): Answers = sequence {
|
): Answers = sequence {
|
||||||
val t1 = applySubstitution(term1, subs)
|
val t1 = applySubstitution(term1, subs)
|
||||||
val t2 = applySubstitution(term2, subs)
|
val t2 = applySubstitution(term2, subs)
|
||||||
|
@ -101,8 +107,8 @@ fun operate(
|
||||||
val e2 = t2.simplify(subs)
|
val e2 = t2.simplify(subs)
|
||||||
val e3 = t3.simplify(subs)
|
val e3 = t3.simplify(subs)
|
||||||
|
|
||||||
val int3Value = op(e1.to as Integer, e2.to as Integer)
|
val int3Value = op(e1.to as Number, e2.to as Number)
|
||||||
if (int3Value == e3.to as Integer) {
|
if (equivalent(int3Value, e3.to, emptyMap())) {
|
||||||
val opSubs: Substitutions = listOfNotNull(e1.mapped, e2.mapped, e3.mapped)
|
val opSubs: Substitutions = listOfNotNull(e1.mapped, e2.mapped, e3.mapped)
|
||||||
.filter{ pair: Pair<Term, Term>? -> pair != null && !subs.contains(pair.first) }
|
.filter{ pair: Pair<Term, Term>? -> pair != null && !subs.contains(pair.first) }
|
||||||
.toMap()
|
.toMap()
|
||||||
|
@ -114,7 +120,7 @@ fun operate(
|
||||||
val e1 = t1.simplify(subs)
|
val e1 = t1.simplify(subs)
|
||||||
val e2 = t2.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
|
val int3 = t3 as Variable
|
||||||
yield(Result.success(mapOf(int3 to int3Value) + listOfNotNull(e1.mapped, e2.mapped)))
|
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 e = if (nonvariable(t1, subs)) t1.simplify(subs) else t2.simplify(subs)
|
||||||
val e3 = t3.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
|
val int = t as Variable
|
||||||
yield(Result.success(mapOf(int to value) + listOfNotNull(e.mapped, e3.mapped)))
|
yield(Result.success(mapOf(int to value) + listOfNotNull(e.mapped, e3.mapped)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ import prolog.ast.arithmetic.Expression
|
||||||
import prolog.ast.logic.LogicOperator
|
import prolog.ast.logic.LogicOperator
|
||||||
import prolog.ast.terms.*
|
import prolog.ast.terms.*
|
||||||
import kotlin.NoSuchElementException
|
import kotlin.NoSuchElementException
|
||||||
|
import prolog.ast.arithmetic.Number
|
||||||
|
import prolog.ast.arithmetic.Integer
|
||||||
|
import prolog.ast.arithmetic.Float
|
||||||
|
|
||||||
// Apply substitutions to a term
|
// Apply substitutions to a term
|
||||||
fun applySubstitution(term: Term, subs: Substitutions): Term = when {
|
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 Atom && term2 is Atom -> compare(term1, term2, subs) == 0
|
||||||
term1 is Structure && term2 is Structure -> 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 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 && term2 is Variable -> term1 == term2
|
||||||
term1 is Variable -> term1 in subs && equivalent(subs[term1]!!, term2, subs)
|
term1 is Variable -> term1 in subs && equivalent(subs[term1]!!, term2, subs)
|
||||||
term2 is Variable -> term2 in subs && equivalent(subs[term2]!!, term1, 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 -> {
|
is Variable -> {
|
||||||
when (t2) {
|
when (t2) {
|
||||||
is Variable -> t1.name.compareTo(t2.name)
|
is Variable -> t1.name.compareTo(t2.name)
|
||||||
is Integer -> -1
|
is Number -> -1
|
||||||
is Atom -> -1
|
is Atom -> -1
|
||||||
is Structure -> -1
|
is Structure -> -1
|
||||||
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
|
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Integer -> {
|
is Number -> {
|
||||||
when (t2) {
|
when (t2) {
|
||||||
is Variable -> 1
|
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 Atom -> -1
|
||||||
is Structure -> -1
|
is Structure -> -1
|
||||||
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
|
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
|
||||||
|
@ -137,7 +142,7 @@ fun compare(term1: Term, term2: Term, subs: Substitutions): Int {
|
||||||
is Atom -> {
|
is Atom -> {
|
||||||
when (t2) {
|
when (t2) {
|
||||||
is Variable -> 1
|
is Variable -> 1
|
||||||
is Integer -> 1
|
is Number -> 1
|
||||||
is Atom -> t1.name.compareTo(t2.name)
|
is Atom -> t1.name.compareTo(t2.name)
|
||||||
is Structure -> -1
|
is Structure -> -1
|
||||||
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
|
else -> throw IllegalArgumentException("Cannot compare $t1 with $t2")
|
||||||
|
@ -146,7 +151,7 @@ fun compare(term1: Term, term2: Term, subs: Substitutions): Int {
|
||||||
is Structure -> {
|
is Structure -> {
|
||||||
when (t2) {
|
when (t2) {
|
||||||
is Variable -> 1
|
is Variable -> 1
|
||||||
is Integer -> 1
|
is Number -> 1
|
||||||
is Atom -> 1
|
is Atom -> 1
|
||||||
is Structure -> {
|
is Structure -> {
|
||||||
val arityComparison = t1.arguments.size.compareTo(t2.arguments.size)
|
val arityComparison = t1.arguments.size.compareTo(t2.arguments.size)
|
||||||
|
|
|
@ -4,8 +4,8 @@ import org.junit.jupiter.api.Assertions.*
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.assertThrows
|
import org.junit.jupiter.api.assertThrows
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.terms.Integer
|
import prolog.ast.arithmetic.Float
|
||||||
import prolog.ast.terms.Term
|
import prolog.ast.arithmetic.Integer
|
||||||
import prolog.ast.terms.Variable
|
import prolog.ast.terms.Variable
|
||||||
import prolog.logic.equivalent
|
import prolog.logic.equivalent
|
||||||
|
|
||||||
|
@ -285,6 +285,111 @@ class ArithmeticOperatorsTests {
|
||||||
assertEquals(0, result.size, "X should not be equal to Y")
|
assertEquals(0, result.size, "X should not be equal to Y")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `var is mul`() {
|
||||||
|
val op = Is(
|
||||||
|
Variable("X"),
|
||||||
|
Multiply(Integer(2), Integer(3))
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = op.satisfy(emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X should be equal to 6")
|
||||||
|
assertTrue(result[0].isSuccess, "X should be equal to 6")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertEquals(1, subs.size, "X should be rebound")
|
||||||
|
assertTrue(
|
||||||
|
equivalent(Integer(6), subs[Variable("X")]!!, emptyMap()),
|
||||||
|
"X should be equal to 6"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `bound-var is mul`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
|
||||||
|
val op = Is(
|
||||||
|
t1,
|
||||||
|
Multiply(Integer(2), Integer(3))
|
||||||
|
)
|
||||||
|
val map: Substitutions = mapOf(t1 to Integer(6))
|
||||||
|
|
||||||
|
val result = op.satisfy(map).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X should be equal to 6")
|
||||||
|
assertTrue(result[0].isSuccess, "X should be equal to 6")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertTrue(subs.isEmpty(), "X should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `var is bound-to-mul`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
val t2 = Variable("Y")
|
||||||
|
|
||||||
|
val op = Is(t1, t2)
|
||||||
|
val map: Substitutions = mapOf(t1 to Integer(6), t2 to Multiply(Integer(2), Integer(3)))
|
||||||
|
|
||||||
|
val result = op.satisfy(map).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X should be equal to Y")
|
||||||
|
assertTrue(result[0].isSuccess, "X should be equal to Y")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertTrue(subs.isEmpty(), "X should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `2 is 4 div 2`() {
|
||||||
|
val op = Is(
|
||||||
|
Integer(2),
|
||||||
|
Divide(Integer(4), Integer(2))
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = op.satisfy(emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "2 should be equal to 4 / 2")
|
||||||
|
assertTrue(result[0].isSuccess, "2 should be equal to 4 / 2")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertTrue(subs.isEmpty(), "2 should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `4 div 2 is var`() {
|
||||||
|
val op = Is(
|
||||||
|
Variable("X"),
|
||||||
|
Divide(Integer(4), Integer(2))
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = op.satisfy(emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X should be equal to 2")
|
||||||
|
assertTrue(result[0].isSuccess, "X should be equal to 2")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertEquals(1, subs.size, "X should be rebound")
|
||||||
|
assertTrue(
|
||||||
|
equivalent(Integer(2), subs[Variable("X")]!!, emptyMap()),
|
||||||
|
"X should be equal to 2"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `bound-var is 4 div 2`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
|
||||||
|
val op = Is(
|
||||||
|
t1,
|
||||||
|
Divide(Integer(4), Integer(2))
|
||||||
|
)
|
||||||
|
val map: Substitutions = mapOf(t1 to Integer(2))
|
||||||
|
|
||||||
|
val result = op.satisfy(map).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X should be equal to 2")
|
||||||
|
assertTrue(result[0].isSuccess, "X should be equal to 2")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertTrue(subs.isEmpty(), "X should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ?- between(1, 2, X), Y is 1 + X.
|
* ?- between(1, 2, X), Y is 1 + X.
|
||||||
* X = 1, Y = 2 ;
|
* X = 1, Y = 2 ;
|
||||||
|
@ -441,4 +546,44 @@ class ArithmeticOperatorsTests {
|
||||||
|
|
||||||
assertEquals(Integer(6), result.to, "2 * 3 should be equal to 6")
|
assertEquals(Integer(6), result.to, "2 * 3 should be equal to 6")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Divide 1 and 1 to get 1`() {
|
||||||
|
val t1 = Integer(1)
|
||||||
|
val t2 = Integer(1)
|
||||||
|
|
||||||
|
val result = Divide(t1, t2).simplify(emptyMap())
|
||||||
|
|
||||||
|
assertEquals(Integer(1), result.to, "1 / 1 should be equal to 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Divide 2 and 2 to get 1`() {
|
||||||
|
val t1 = Integer(2)
|
||||||
|
val t2 = Integer(2)
|
||||||
|
|
||||||
|
val result = Divide(t1, t2).simplify(emptyMap())
|
||||||
|
|
||||||
|
assertEquals(Integer(1), result.to, "2 / 2 should be equal to 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Divide 12 and 3 to get 4`() {
|
||||||
|
val t1 = Integer(12)
|
||||||
|
val t2 = Integer(3)
|
||||||
|
|
||||||
|
val result = Divide(t1, t2).simplify(emptyMap())
|
||||||
|
|
||||||
|
assertEquals(Integer(4), result.to, "12 / 3 should be equal to 4")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Divide 1 and 2 to get float`() {
|
||||||
|
val t1 = Integer(1)
|
||||||
|
val t2 = Integer(2)
|
||||||
|
|
||||||
|
val result = Divide(t1, t2).simplify(emptyMap())
|
||||||
|
|
||||||
|
assertTrue(equivalent(result.to, Float(0.5f), emptyMap()), "1 / 2 should be equal to 0.5")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import prolog.ast.logic.Fact
|
||||||
import prolog.ast.logic.Rule
|
import prolog.ast.logic.Rule
|
||||||
import prolog.ast.terms.Atom
|
import prolog.ast.terms.Atom
|
||||||
import prolog.ast.terms.CompoundTerm
|
import prolog.ast.terms.CompoundTerm
|
||||||
import prolog.ast.terms.Integer
|
import prolog.ast.arithmetic.Integer
|
||||||
import prolog.ast.terms.Variable
|
import prolog.ast.terms.Variable
|
||||||
|
|
||||||
class ControlOperatorsTests {
|
class ControlOperatorsTests {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package prolog.builtins
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.jupiter.api.Assertions.*
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import prolog.ast.terms.Atom
|
import prolog.ast.terms.Atom
|
||||||
import prolog.ast.terms.Integer
|
import prolog.ast.arithmetic.Integer
|
||||||
import prolog.ast.terms.Variable
|
import prolog.ast.terms.Variable
|
||||||
|
|
||||||
class UnificationTest {
|
class UnificationTest {
|
||||||
|
|
|
@ -5,7 +5,8 @@ import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
import org.junit.jupiter.api.RepeatedTest
|
import org.junit.jupiter.api.RepeatedTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.terms.Integer
|
import prolog.ast.arithmetic.Integer
|
||||||
|
import prolog.ast.arithmetic.Float
|
||||||
import prolog.ast.terms.Term
|
import prolog.ast.terms.Term
|
||||||
import prolog.ast.terms.Variable
|
import prolog.ast.terms.Variable
|
||||||
|
|
||||||
|
@ -141,6 +142,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "1 + 2 should be equal to 3")
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "1 + 2 should be equal to 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 + 2,0 = 3,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Float(3.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "1.0 + 1.0 should already be equal to 2.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1_plus_2_is_not_4`() {
|
fun `1_plus_2_is_not_4`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -152,6 +166,17 @@ class ArithmeticTests {
|
||||||
assertTrue(result.none(), "1 + 2 should not be equal to 4")
|
assertTrue(result.none(), "1 + 2 should not be equal to 4")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus 2,0 is not 4,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Float(4.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, emptyMap())
|
||||||
|
|
||||||
|
assertTrue(result.none(), "1.0 + 2.0 should not be equal to 4.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1_plus_2_is_variable`() {
|
fun `1_plus_2_is_variable`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -165,6 +190,22 @@ class ArithmeticTests {
|
||||||
assertEquals(Integer(3), result[0].getOrNull()!![t3], "X should be equal to 3")
|
assertEquals(Integer(3), result[0].getOrNull()!![t3], "X should be equal to 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus 2,0 is variable`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Variable("X")
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "1.0 + 2.0 should be equal to X")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
|
||||||
|
assertTrue(equivalent(Float(3.0f), subs[t3]!!, emptyMap()), "X should be equal to 3.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1_plus_variable_is_3`() {
|
fun `1_plus_variable_is_3`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -178,6 +219,22 @@ class ArithmeticTests {
|
||||||
assertEquals(Integer(2), result[0].getOrNull()!![t2], "X should be equal to 2")
|
assertEquals(Integer(2), result[0].getOrNull()!![t2], "X should be equal to 2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus variable is 3,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Variable("X")
|
||||||
|
val t3 = Float(3.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "1.0 + X should be equal to 3.0")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
|
||||||
|
assertTrue(equivalent(Float(2.0f), subs[t2]!!, emptyMap()), "X should be equal to 2.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun variable_plus_2_is_3() {
|
fun variable_plus_2_is_3() {
|
||||||
val t1 = Variable("X")
|
val t1 = Variable("X")
|
||||||
|
@ -191,6 +248,22 @@ class ArithmeticTests {
|
||||||
assertEquals(Integer(1), result[0].getOrNull()!![t1], "X should be equal to 1")
|
assertEquals(Integer(1), result[0].getOrNull()!![t1], "X should be equal to 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `variable plus 2,0 is 3,0`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Float(3.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X + 2.0 should be equal to 3.0")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
|
||||||
|
assertTrue(equivalent(Float(1.0f), subs[t1]!!, emptyMap()), "X should be equal to 1.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1 plus 2 is bound-to-3-var`() {
|
fun `1 plus 2 is bound-to-3-var`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -204,6 +277,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "t3 should not be rebound")
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "t3 should not be rebound")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus 2,0 is bound-to-3,0-var`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Variable("X")
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, mapOf(Variable("X") to Float(3.0f))).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "1.0 + 2.0 should be equal to X")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "t3 should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1 plus 2 is bound-to-4-var`() {
|
fun `1 plus 2 is bound-to-4-var`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -215,6 +301,17 @@ class ArithmeticTests {
|
||||||
assertTrue(result.none(), "1 + 2 should not be equal to X")
|
assertTrue(result.none(), "1 + 2 should not be equal to X")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus 2,0 is bound-to-4,0-var`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Variable("X")
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, mapOf(t3 to Float(4.0f)))
|
||||||
|
|
||||||
|
assertTrue(result.none(), "1.0 + 2.0 should not be equal to X")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1 plus bound-to-2-var is 3`() {
|
fun `1 plus bound-to-2-var is 3`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -228,6 +325,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "t2 should not be rebound")
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "t2 should not be rebound")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus bound-to-2,0-var is 3,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Variable("X")
|
||||||
|
val t3 = Float(3.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, mapOf(t2 to Float(2.0f))).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "1.0 + X should be equal to 3.0")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "t2 should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1 plus bound-to-2-var is not 4`() {
|
fun `1 plus bound-to-2-var is not 4`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -239,6 +349,17 @@ class ArithmeticTests {
|
||||||
assertTrue(result.none(), "1 + X should not be equal to 4")
|
assertTrue(result.none(), "1 + X should not be equal to 4")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 plus bound-to-2,0-var is not 4,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Variable("X")
|
||||||
|
val t3 = Float(4.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, mapOf(t2 to Float(2.0f)))
|
||||||
|
|
||||||
|
assertTrue(result.none(), "1.0 + X should not be equal to 4.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `bound-to-1-var plus 2 is 3`() {
|
fun `bound-to-1-var plus 2 is 3`() {
|
||||||
val t1 = Variable("X")
|
val t1 = Variable("X")
|
||||||
|
@ -252,6 +373,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.none(), "t1 should not be rebound")
|
assertTrue(result[0].getOrNull()!!.none(), "t1 should not be rebound")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `bound-to-1-var plus 2,0 is 3,0`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Float(3.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, mapOf(t1 to Integer(1))).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "X + 2.0 should be equal to 3.0")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.none(), "t1 should not be rebound")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `bound-to-1-var plus 2 is not 4`() {
|
fun `bound-to-1-var plus 2 is not 4`() {
|
||||||
val t1 = Variable("X")
|
val t1 = Variable("X")
|
||||||
|
@ -263,6 +397,17 @@ class ArithmeticTests {
|
||||||
assertTrue(result.none(), "X + 2 should not be equal to 4")
|
assertTrue(result.none(), "X + 2 should not be equal to 4")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `bound-to-1-var plus 2,0 is not 4,0`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Float(4.0f)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, mapOf(t1 to Integer(1)))
|
||||||
|
|
||||||
|
assertTrue(result.none(), "X + 2.0 should not be equal to 4.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `two unbound vars plus should throw`() {
|
fun `two unbound vars plus should throw`() {
|
||||||
val t1 = Variable("X")
|
val t1 = Variable("X")
|
||||||
|
@ -294,6 +439,37 @@ class ArithmeticTests {
|
||||||
assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Integer(3), result[0].getOrNull()!!), "Z should be equal to 3")
|
assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Integer(3), result[0].getOrNull()!!), "Z should be equal to 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `bound-to-1,0-var plus bound-to-2,0-var is variable`() {
|
||||||
|
val t1 = Variable("X")
|
||||||
|
val t2 = Variable("Y")
|
||||||
|
val t3 = Variable("Z")
|
||||||
|
|
||||||
|
val map: Substitutions = mapOf(
|
||||||
|
t1 to Float(1.0f),
|
||||||
|
t2 to Float(2.0f),
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, map).toList()
|
||||||
|
|
||||||
|
assertTrue(result.isNotEmpty(), "X + Y should be equal to Z")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Float(3.0f), result[0].getOrNull()!!), "Z should be equal to 3.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `int + float is float`() {
|
||||||
|
val t1 = Integer(1)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Variable("X")
|
||||||
|
|
||||||
|
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Float(3.0f), result[0].getOrNull()!!), "X should be equal to 3.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1 times 1 is 1`() {
|
fun `1 times 1 is 1`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -307,6 +483,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "1 * 1 should already be equal to 1")
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "1 * 1 should already be equal to 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 times 1,0 is 1,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(1.0f)
|
||||||
|
val t3 = Float(1.0f)
|
||||||
|
|
||||||
|
val result = mul(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "1.0 * 1.0 should already be equal to 1.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `1 times 2 is 2`() {
|
fun `1 times 2 is 2`() {
|
||||||
val t1 = Integer(1)
|
val t1 = Integer(1)
|
||||||
|
@ -320,6 +509,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "1 * 2 should already be equal to 2")
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "1 * 2 should already be equal to 2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `1,0 times 2,0 is 2,0`() {
|
||||||
|
val t1 = Float(1.0f)
|
||||||
|
val t2 = Float(2.0f)
|
||||||
|
val t3 = Float(2.0f)
|
||||||
|
|
||||||
|
val result = mul(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "1.0 * 2.0 should already be equal to 2.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `2 times 3 is 6`() {
|
fun `2 times 3 is 6`() {
|
||||||
val t1 = Integer(2)
|
val t1 = Integer(2)
|
||||||
|
@ -333,6 +535,19 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "2 * 3 should already be equal to 6")
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "2 * 3 should already be equal to 6")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `2,0 times 3,0 is 6,0`() {
|
||||||
|
val t1 = Float(2.0f)
|
||||||
|
val t2 = Float(3.0f)
|
||||||
|
val t3 = Float(6.0f)
|
||||||
|
|
||||||
|
val result = mul(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(result[0].getOrNull()!!.isEmpty(), "2.0 * 3.0 should already be equal to 6.0")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `2 times 3 is not 4`() {
|
fun `2 times 3 is not 4`() {
|
||||||
val t1 = Integer(2)
|
val t1 = Integer(2)
|
||||||
|
@ -344,6 +559,30 @@ class ArithmeticTests {
|
||||||
assertTrue(result.none(), "2 * 3 should not be equal to 4")
|
assertTrue(result.none(), "2 * 3 should not be equal to 4")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `2,0 times 3,0 is not 4,0`() {
|
||||||
|
val t1 = Float(2.0f)
|
||||||
|
val t2 = Float(3.0f)
|
||||||
|
val t3 = Float(4.0f)
|
||||||
|
|
||||||
|
val result = mul(t1, t2, t3, emptyMap())
|
||||||
|
|
||||||
|
assertTrue(result.none(), "2.0 * 3.0 should not be equal to 4.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `int times float is float`() {
|
||||||
|
val t1 = Integer(2)
|
||||||
|
val t2 = Float(3.0f)
|
||||||
|
val t3 = Variable("X")
|
||||||
|
|
||||||
|
val result = mul(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Float(6.0f), result[0].getOrNull()!!), "X should be equal to 6.0")
|
||||||
|
}
|
||||||
|
|
||||||
@RepeatedTest(100)
|
@RepeatedTest(100)
|
||||||
fun `random test for mul`() {
|
fun `random test for mul`() {
|
||||||
val t1 = Integer((0..1000).random())
|
val t1 = Integer((0..1000).random())
|
||||||
|
@ -356,4 +595,18 @@ class ArithmeticTests {
|
||||||
assertTrue(result[0].isSuccess, "Expected success")
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
assertEquals(Integer(t1.value * t2.value), result[0].getOrNull()!![t3], "X should be equal to ${t1.value * t2.value}")
|
assertEquals(Integer(t1.value * t2.value), result[0].getOrNull()!![t3], "X should be equal to ${t1.value * t2.value}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RepeatedTest(100)
|
||||||
|
fun `random test for mul with floats`() {
|
||||||
|
val t1 = Float((0..1000).random().toFloat())
|
||||||
|
val t2 = Float((0..1000).random().toFloat())
|
||||||
|
val t3 = Variable("X")
|
||||||
|
|
||||||
|
val result = mul(t1, t2, t3, emptyMap()).toList()
|
||||||
|
|
||||||
|
assertEquals(1, result.size, "There should be one solution")
|
||||||
|
assertTrue(result[0].isSuccess, "Expected success")
|
||||||
|
val subs = result[0].getOrNull()!!
|
||||||
|
assertTrue(equivalent(subs[t3]!!, Float(t1.value * t2.value), subs), "X should be equal to ${t1.value * t2.value}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions.*
|
||||||
import org.junit.jupiter.api.Disabled
|
import org.junit.jupiter.api.Disabled
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.terms.Integer
|
import prolog.ast.arithmetic.Integer
|
||||||
import prolog.ast.terms.Atom
|
import prolog.ast.terms.Atom
|
||||||
import prolog.ast.terms.Structure
|
import prolog.ast.terms.Structure
|
||||||
import prolog.ast.terms.Variable
|
import prolog.ast.terms.Variable
|
||||||
|
|
Reference in a new issue