refactor: Rework
This commit is contained in:
parent
ac55ed4c64
commit
6469dd6ced
34 changed files with 593 additions and 552 deletions
|
@ -200,7 +200,7 @@ class EvaluationTest {
|
|||
|
||||
Program.load(listOf(fact1, fact2, fact3))
|
||||
|
||||
val results = Query(Structure(Atom("a"), listOf(Variable("X")))).prove(emptyMap())
|
||||
val results = Query(Structure(Atom("a"), listOf(Variable("X")))).satisfy(emptyMap())
|
||||
|
||||
val expectedResults = listOf(
|
||||
mapOf(Variable("X") to Atom("b")),
|
||||
|
@ -211,8 +211,8 @@ class EvaluationTest {
|
|||
|
||||
assertEquals(expectedResults.size, actualResults.size, "Number of results should match")
|
||||
for (i in expectedResults.indices) {
|
||||
assertEquals(expectedResults[i].size, actualResults[i].size, "Substitution size should match")
|
||||
assertTrue(expectedResults[i].all { actualResults[i][it.key]?.let { it1 -> equivalent(it.value, it1) } ?: false }, "Substitution values should match")
|
||||
assertEquals(expectedResults[i].size, actualResults[i].getOrNull()!!.size, "Substitution size should match")
|
||||
assertTrue(expectedResults[i].all { actualResults[i].getOrNull()!![it.key]?.let { it1 -> equivalent(it.value, it1, emptyMap()) } ?: false }, "Substitution values should match")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,9 +3,10 @@ package prolog.builtins
|
|||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.terms.Integer
|
||||
import prolog.ast.terms.Term
|
||||
import prolog.ast.terms.Variable
|
||||
import prolog.logic.between
|
||||
import prolog.logic.equivalent
|
||||
|
||||
class ArithmeticOperatorsTests {
|
||||
|
@ -16,18 +17,21 @@ class ArithmeticOperatorsTests {
|
|||
Integer(1)
|
||||
)
|
||||
|
||||
var result = op1.evaluate(emptyMap()).first
|
||||
var result = op1.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(True, result, "1 should be equal to 1")
|
||||
assertEquals(1, result.size, "1 should be equal to 1")
|
||||
assertTrue(result[0].isSuccess, "1 should be equal to 1")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "1 should not be rebound")
|
||||
|
||||
val op2 = EvaluatesToDifferent(
|
||||
Integer(1),
|
||||
Integer(1)
|
||||
)
|
||||
|
||||
result = op2.evaluate(emptyMap()).first
|
||||
result = op2.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(False, result, "1 should not be different from 1")
|
||||
assertEquals(0, result.size, "1 should not be different from 1")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -37,18 +41,21 @@ class ArithmeticOperatorsTests {
|
|||
Integer(2)
|
||||
)
|
||||
|
||||
var result = op1.evaluate(emptyMap()).first
|
||||
var result = op1.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(0, result.size, "1 should not be equal to 2")
|
||||
|
||||
assertEquals(False, result, "1 should not be equal to 2")
|
||||
|
||||
val op2 = EvaluatesToDifferent(
|
||||
Integer(1),
|
||||
Integer(2)
|
||||
)
|
||||
|
||||
result = op2.evaluate(emptyMap()).first
|
||||
result = op2.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(True, result, "1 should be different from 2")
|
||||
assertEquals(1, result.size, "1 should be different from 2")
|
||||
assertTrue(result[0].isSuccess, "1 should be different from 2")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "1 should not be rebound")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -58,18 +65,21 @@ class ArithmeticOperatorsTests {
|
|||
Integer(5)
|
||||
)
|
||||
|
||||
var result = op.evaluate(emptyMap()).first
|
||||
var result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(True, result, "2 + 3 should be equal to 5")
|
||||
assertEquals(1, result.size, "2 + 3 should be equal to 5")
|
||||
assertTrue(result[0].isSuccess, "2 + 3 should be equal to 5")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "2 + 3 should not be rebound")
|
||||
|
||||
val op2 = EvaluatesToDifferent(
|
||||
Add(Integer(2), Integer(3)),
|
||||
Integer(5)
|
||||
)
|
||||
|
||||
result = op2.evaluate(emptyMap()).first
|
||||
result = op2.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(False, result, "2 + 3 should not be different from 5")
|
||||
assertEquals(0, result.size, "2 + 3 should not be different from 5")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -79,18 +89,21 @@ class ArithmeticOperatorsTests {
|
|||
Add(Integer(4), Integer(1))
|
||||
)
|
||||
|
||||
var result = op.evaluate(emptyMap()).first
|
||||
var result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(True, result, "2 + 3 should be equal to 4 + 1")
|
||||
assertEquals(1, result.size, "2 + 3 should be equal to 4 + 1")
|
||||
assertTrue(result[0].isSuccess, "2 + 3 should be equal to 4 + 1")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "2 + 3 should not be rebound")
|
||||
|
||||
val op2 = EvaluatesToDifferent(
|
||||
Add(Integer(2), Integer(3)),
|
||||
Add(Integer(4), Integer(1))
|
||||
)
|
||||
|
||||
result = op2.evaluate(emptyMap()).first
|
||||
result = op2.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(False, result, "2 + 3 should not be different from 4 + 1")
|
||||
assertEquals(0, result.size, "2 + 3 should not be different from 4 + 1")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -100,14 +113,24 @@ class ArithmeticOperatorsTests {
|
|||
Variable("X")
|
||||
)
|
||||
|
||||
assertThrows<IllegalArgumentException> { op.evaluate(emptyMap()) }
|
||||
var result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "One exception should be thrown")
|
||||
assertTrue(result[0].isFailure, "One exception should be thrown")
|
||||
var exceptions = result[0].exceptionOrNull()
|
||||
assertTrue(exceptions is IllegalArgumentException, "One exception should be thrown")
|
||||
|
||||
val op2 = EvaluatesToDifferent(
|
||||
Integer(1),
|
||||
Variable("X")
|
||||
)
|
||||
|
||||
assertThrows<IllegalArgumentException> { op2.evaluate(emptyMap()) }
|
||||
result = op2.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "One exception should be thrown")
|
||||
assertTrue(result[0].isFailure, "One exception should be thrown")
|
||||
exceptions = result[0].exceptionOrNull()
|
||||
assertTrue(exceptions is IllegalArgumentException, "One exception should be thrown")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -117,14 +140,14 @@ class ArithmeticOperatorsTests {
|
|||
Integer(1)
|
||||
)
|
||||
|
||||
assertThrows<IllegalArgumentException> { op.evaluate(emptyMap()) }
|
||||
assertThrows<IllegalArgumentException> { op.satisfy(emptyMap()) }
|
||||
|
||||
val op2 = EvaluatesToDifferent(
|
||||
Add(Integer(1), Variable("X")),
|
||||
Integer(1)
|
||||
)
|
||||
|
||||
assertThrows<IllegalArgumentException> { op2.evaluate(emptyMap()) }
|
||||
assertThrows<IllegalArgumentException> { op2.satisfy(emptyMap()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -134,7 +157,7 @@ class ArithmeticOperatorsTests {
|
|||
Integer(1)
|
||||
)
|
||||
|
||||
val result = op.prove(emptyMap())
|
||||
val result = op.satisfy(emptyMap())
|
||||
|
||||
assertTrue(result.any(), "1 should be equal to 1")
|
||||
}
|
||||
|
@ -146,7 +169,7 @@ class ArithmeticOperatorsTests {
|
|||
Integer(2)
|
||||
)
|
||||
|
||||
val result = op.prove(emptyMap()).toList()
|
||||
val result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertTrue(result.isEmpty(), "1 should not be equal to 2")
|
||||
}
|
||||
|
@ -159,12 +182,11 @@ class ArithmeticOperatorsTests {
|
|||
Integer(1)
|
||||
)
|
||||
|
||||
t1.bind(Integer(1))
|
||||
val result = op.satisfy(mapOf(t1 to Integer(1))).toList()
|
||||
|
||||
val result = op.prove(emptyMap())
|
||||
|
||||
assertTrue(result.any(), "X should be equal to 1")
|
||||
assertTrue(result.first().isEmpty(), "X should not be rebound")
|
||||
assertEquals(1, result.size, "X should be equal to 1")
|
||||
assertTrue(result.first().isSuccess, "X should be equal to 1")
|
||||
assertTrue(result.first().getOrNull()!!.isEmpty(), "X should not be rebound")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -175,9 +197,7 @@ class ArithmeticOperatorsTests {
|
|||
Integer(1)
|
||||
)
|
||||
|
||||
t1.bind(Integer(2))
|
||||
|
||||
val result = op.prove(emptyMap())
|
||||
val result = op.satisfy(mapOf(t1 to Integer(2)))
|
||||
|
||||
assertFalse(result.any(), "X should not be equal to 1")
|
||||
}
|
||||
|
@ -189,11 +209,12 @@ class ArithmeticOperatorsTests {
|
|||
Integer(1)
|
||||
)
|
||||
|
||||
val result = op.prove(emptyMap()).toList()
|
||||
val result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertFalse(result.isEmpty(), "X should be equal to 1")
|
||||
assertEquals(1, result[0].size, "X should be rebound")
|
||||
assertTrue(equivalent(Integer(1), result[0][Variable("X")]!!), "X should be equal to 1")
|
||||
assertTrue(result.first().isSuccess, "X should be equal to 1")
|
||||
assertEquals(1, result[0].getOrNull()!!.size, "X should be rebound")
|
||||
assertTrue(equivalent(Integer(1), result[0].getOrNull()!![Variable("X")]!!, emptyMap()), "X should be equal to 1")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -203,11 +224,18 @@ class ArithmeticOperatorsTests {
|
|||
Add(Integer(1), Integer(2))
|
||||
)
|
||||
|
||||
val result = op.prove(emptyMap()).toList()
|
||||
val result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertFalse(result.isEmpty(), "X should be equal to 3")
|
||||
assertEquals(1, result[0].size, "X should be rebound")
|
||||
assertTrue(equivalent(Integer(3), result[0][Variable("X")]!!), "X should be equal to 3")
|
||||
assertTrue(result.first().isSuccess, "X should be equal to 3")
|
||||
|
||||
val subs = result[0].getOrNull()!!
|
||||
|
||||
assertEquals(1, subs.size, "X should be rebound")
|
||||
assertTrue(
|
||||
equivalent(Integer(3), subs[Variable("X")]!!, emptyMap()),
|
||||
"X should be equal to 3"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -217,7 +245,12 @@ class ArithmeticOperatorsTests {
|
|||
Variable("Y")
|
||||
)
|
||||
|
||||
assertThrows<IllegalArgumentException> { op.prove(emptyMap()) }
|
||||
val result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "One exception should be thrown")
|
||||
assertTrue(result[0].isFailure, "One exception should be thrown")
|
||||
val exceptions = result[0].exceptionOrNull()
|
||||
assertTrue(exceptions is IllegalArgumentException, "One exception should be thrown")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -227,23 +260,29 @@ class ArithmeticOperatorsTests {
|
|||
Variable("X")
|
||||
)
|
||||
|
||||
assertThrows<IllegalArgumentException> { op.prove(emptyMap()) }
|
||||
val result = op.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "One exception should be thrown")
|
||||
assertTrue(result[0].isFailure, "One exception should be thrown")
|
||||
val exceptions = result[0].exceptionOrNull()
|
||||
assertTrue(exceptions is IllegalArgumentException, "One exception should be thrown")
|
||||
}
|
||||
|
||||
/**
|
||||
* ?- X = 1, Y = 1 + 2, X is Y.
|
||||
* false.
|
||||
*/
|
||||
@Test
|
||||
fun `var is bound-to-sum-var`() {
|
||||
val t1 = Variable("X")
|
||||
val t2 = Variable("Y")
|
||||
|
||||
t2.bind(Add(Integer(1), Integer(2)))
|
||||
|
||||
val op = Is(t1, t2)
|
||||
val map: Substitutions = mapOf(t1 to Integer(1), t2 to Add(Integer(1), Integer(2)))
|
||||
|
||||
val result = op.prove(emptyMap()).toList()
|
||||
val result = op.satisfy(map).toList()
|
||||
|
||||
assertTrue(result.isNotEmpty(), "X should be equal to 3")
|
||||
assertEquals(1, result[0].size, "X should be rebound, Y should not")
|
||||
assertTrue(equivalent(Integer(3), result[0][t1]!!), "X should be equal to 3")
|
||||
assertEquals(0, result.size, "X should not be equal to Y")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,47 +307,38 @@ class ArithmeticOperatorsTests {
|
|||
fun `negate 1 to get -1`() {
|
||||
val t1 = Integer(1)
|
||||
|
||||
val result = Negate(t1).evaluate(emptyMap()).first
|
||||
val result = Negate(t1).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(-1), result, "negate(1) should be equal to -1")
|
||||
assertEquals(Integer(-1), result.to, "negate(1) should be equal to -1")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `negate 0 to get 0`() {
|
||||
val t1 = Integer(0)
|
||||
|
||||
val result = Negate(t1).evaluate(emptyMap()).first
|
||||
val result = Negate(t1).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(0), result, "negate(0) should be equal to 0")
|
||||
assertEquals(Integer(0), result.to, "negate(0) should be equal to 0")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `negate -1 to get 1`() {
|
||||
val t1 = Integer(-1)
|
||||
|
||||
val result = Negate(t1).evaluate(emptyMap()).first
|
||||
val result = Negate(t1).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(1), result, "negate(-1) should be equal to 1")
|
||||
assertEquals(Integer(1), result.to, "negate(-1) should be equal to 1")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `negate bound-to-1-var to get -1`() {
|
||||
val t1 = Variable("X")
|
||||
|
||||
t1.bind(Integer(1))
|
||||
val map: Substitutions = mapOf(t1 to Integer(1))
|
||||
|
||||
val result = Negate(t1).evaluate(emptyMap()).first
|
||||
val result = Negate(t1).simplify(map)
|
||||
|
||||
assertEquals(Integer(-1), result, "negate(1) should be equal to -1")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `negate bound-to-1-var to get -1 by map`() {
|
||||
val t1 = Variable("X")
|
||||
|
||||
val result = Negate(t1).evaluate(mapOf(t1 to Integer(1))).first
|
||||
|
||||
assertEquals(Integer(-1), result, "negate(1) should be equal to -1")
|
||||
assertEquals(Integer(-1), result.to, "negate(1) should be equal to -1")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -316,9 +346,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(1)
|
||||
val t2 = Integer(3)
|
||||
|
||||
val result = Negate(Add(t1, t2)).evaluate(emptyMap()).first
|
||||
val result = Negate(Add(t1, t2)).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(-4), result, "negate(1 + 3) should be equal to -4")
|
||||
assertEquals(Integer(-4), result.to, "negate(1 + 3) should be equal to -4")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -326,9 +356,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(1)
|
||||
val t2 = Integer(2)
|
||||
|
||||
val result = Add(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Add(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(3), result, "1 + 2 should be equal to 3")
|
||||
assertEquals(Integer(3), result.to, "1 + 2 should be equal to 3")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -336,21 +366,10 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(1)
|
||||
val t2 = Variable("X")
|
||||
|
||||
t2.bind(Integer(2))
|
||||
val subs: Substitutions = mapOf(t2 to Integer(2))
|
||||
val result = Add(t1, t2).simplify(subs)
|
||||
|
||||
val result = Add(t1, t2).evaluate(emptyMap()).first
|
||||
|
||||
assertEquals(Integer(3), result, "1 + 2 should be equal to 3")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Add 1 and bound-to-2-var to get 3 by map`() {
|
||||
val t1 = Integer(1)
|
||||
val t2 = Variable("X")
|
||||
|
||||
val result = Add(t1, t2).evaluate(mapOf(t2 to Integer(2))).first
|
||||
|
||||
assertEquals(Integer(3), result, "1 + 2 should be equal to 3")
|
||||
assertEquals(Integer(3), result.to, "1 + 2 should be equal to 3")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -358,9 +377,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(1)
|
||||
val t2 = Integer(2)
|
||||
|
||||
val result = Subtract(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Subtract(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(-1), result, "1 - 2 should be equal to -1")
|
||||
assertEquals(Integer(-1), result.to, "1 - 2 should be equal to -1")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -368,9 +387,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(3)
|
||||
val t2 = Integer(1)
|
||||
|
||||
val result = Subtract(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Subtract(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(2), result, "3 - 1 should be equal to 2")
|
||||
assertEquals(Integer(2), result.to, "3 - 1 should be equal to 2")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -378,9 +397,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(0)
|
||||
val t2 = Integer(0)
|
||||
|
||||
val result = Multiply(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Multiply(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(0), result, "0 * 0 should be equal to 0")
|
||||
assertEquals(Integer(0), result.to, "0 * 0 should be equal to 0")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -388,9 +407,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(1)
|
||||
val t2 = Integer(0)
|
||||
|
||||
val result = Multiply(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Multiply(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(0), result, "1 * 0 should be equal to 0")
|
||||
assertEquals(Integer(0), result.to, "1 * 0 should be equal to 0")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -398,9 +417,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(0)
|
||||
val t2 = Integer(1)
|
||||
|
||||
val result = Multiply(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Multiply(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(0), result, "0 * 1 should be equal to 0")
|
||||
assertEquals(Integer(0), result.to, "0 * 1 should be equal to 0")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -408,9 +427,9 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(3)
|
||||
val t2 = Integer(1)
|
||||
|
||||
val result = Multiply(t1, t2).evaluate(emptyMap()).first
|
||||
val result = Multiply(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(3), result, "3 * 1 should be equal to 3")
|
||||
assertEquals(Integer(3), result.to, "3 * 1 should be equal to 3")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -418,8 +437,8 @@ class ArithmeticOperatorsTests {
|
|||
val t1 = Integer(2)
|
||||
val t2 = Integer(3)
|
||||
|
||||
val result = Multiply(t1, t2).evaluate(emptyMap())
|
||||
val result = Multiply(t1, t2).simplify(emptyMap())
|
||||
|
||||
assertEquals(Integer(6), result.first, "2 * 3 should be equal to 6")
|
||||
assertEquals(Integer(6), result.to, "2 * 3 should be equal to 6")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class UnificationTest {
|
|||
val variable = Variable("X")
|
||||
val atom = Atom("a")
|
||||
|
||||
val result = Equivalent(variable, atom).prove(emptyMap())
|
||||
val result = Equivalent(variable, atom).satisfy(emptyMap())
|
||||
|
||||
assertFalse(result.any(), "Variable and atom should not be equivalent")
|
||||
}
|
||||
|
@ -30,10 +30,11 @@ class UnificationTest {
|
|||
val atom1 = Atom("a")
|
||||
val atom2 = Atom("a")
|
||||
|
||||
val result = Equivalent(atom1, atom2).prove(emptyMap())
|
||||
val result = Equivalent(atom1, atom2).satisfy(emptyMap())
|
||||
|
||||
assertTrue(result.any(), "Identical atoms should be equivalent")
|
||||
assertEquals(0, result.first().size, "No substitutions should be made")
|
||||
assertTrue(result.first().isSuccess, "Result should be successful")
|
||||
assertEquals(0, result.first().getOrNull()!!.size, "No substitutions should be made")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,7 +46,7 @@ class UnificationTest {
|
|||
val addition = Add(Integer(1), Integer(2))
|
||||
val solution = Integer(3)
|
||||
|
||||
val result = Equivalent(addition, solution).prove(emptyMap())
|
||||
val result = Equivalent(addition, solution).satisfy(emptyMap())
|
||||
|
||||
assertFalse(result.any(), "Addition should be equivalent")
|
||||
}
|
||||
|
|
|
@ -3,20 +3,19 @@ package prolog.builtins
|
|||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Variable
|
||||
import prolog.logic.compound
|
||||
import prolog.logic.nonvariable
|
||||
import prolog.logic.variable
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class VerificationTest {
|
||||
@Test
|
||||
fun unbound_variable_is_var() {
|
||||
val variable = Variable("X")
|
||||
assertTrue(variable(variable))
|
||||
assertTrue(variable.alias().isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -26,10 +25,8 @@ class VerificationTest {
|
|||
assertTrue(variable(variable))
|
||||
|
||||
val atom = Atom("a")
|
||||
variable.bind(atom)
|
||||
|
||||
assertFalse(variable(variable))
|
||||
assertEquals(atom, variable.alias().get())
|
||||
assertFalse(variable(variable, mapOf(variable to atom)))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -39,10 +36,8 @@ class VerificationTest {
|
|||
assertTrue(variable(variable))
|
||||
|
||||
val structure = Structure(Atom("a"), listOf(Atom("b")))
|
||||
variable.bind(structure)
|
||||
|
||||
assertFalse(variable(variable))
|
||||
assertEquals(structure, variable.alias().get())
|
||||
assertFalse(variable(variable, mapOf(variable to structure)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,8 +47,7 @@ class VerificationTest {
|
|||
@Test
|
||||
fun variable_bound_to_itself_is_var() {
|
||||
val variable = Variable("X")
|
||||
variable.bind(variable)
|
||||
assertTrue(variable(variable))
|
||||
assertTrue(variable(variable, mapOf(variable to variable)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,9 +58,7 @@ class VerificationTest {
|
|||
fun variable_bound_to_another_variable_is_var() {
|
||||
val variable1 = Variable("X")
|
||||
val variable2 = Variable("Y")
|
||||
variable1.bind(variable2)
|
||||
assertTrue(variable(variable1))
|
||||
assertEquals(variable2, variable1.alias().get())
|
||||
assertTrue(variable(variable1, mapOf(variable1 to variable2)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,9 +69,11 @@ class VerificationTest {
|
|||
fun variable_bound_to_bound_variable_is_not_var() {
|
||||
val variable1 = Variable("X")
|
||||
val variable2 = Variable("Y")
|
||||
variable2.bind(Atom("a"))
|
||||
variable1.bind(variable2)
|
||||
assertFalse(variable(variable1))
|
||||
val map: Substitutions = mapOf(
|
||||
variable1 to variable2,
|
||||
variable2 to Atom("a")
|
||||
)
|
||||
assertFalse(variable(variable1, map))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -117,10 +111,8 @@ class VerificationTest {
|
|||
assertFalse(nonvariable(variable))
|
||||
|
||||
val atom = Atom("a")
|
||||
variable.bind(atom)
|
||||
|
||||
assertTrue(nonvariable(variable))
|
||||
assertEquals(atom, variable.alias().get())
|
||||
assertTrue(nonvariable(variable, mapOf(variable to atom)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,10 +126,8 @@ class VerificationTest {
|
|||
assertFalse(nonvariable(variable))
|
||||
|
||||
val structure = Structure(Atom("a"), listOf(Atom("b")))
|
||||
variable.bind(structure)
|
||||
|
||||
assertTrue(nonvariable(variable))
|
||||
assertEquals(structure, variable.alias().get())
|
||||
assertTrue(nonvariable(variable, mapOf(variable to structure)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,8 +137,7 @@ class VerificationTest {
|
|||
@Test
|
||||
fun variable_bound_to_itself_is_not_nonvar() {
|
||||
val variable = Variable("X")
|
||||
variable.bind(variable)
|
||||
assertFalse(nonvariable(variable))
|
||||
assertFalse(nonvariable(variable, mapOf(variable to variable)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,8 +148,7 @@ class VerificationTest {
|
|||
fun variable_bound_to_another_variable_is_not_nonvar() {
|
||||
val variable1 = Variable("X")
|
||||
val variable2 = Variable("Y")
|
||||
variable1.bind(variable2)
|
||||
assertFalse(nonvariable(variable1))
|
||||
assertFalse(nonvariable(variable1, mapOf(variable1 to variable2)))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -195,8 +183,7 @@ class VerificationTest {
|
|||
fun bound_variable_to_atom_is_not_compound() {
|
||||
val variable = Variable("X")
|
||||
val atom = Atom("a")
|
||||
variable.bind(atom)
|
||||
assertFalse(compound(variable))
|
||||
assertFalse(compound(variable, mapOf(variable to atom)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,8 +194,7 @@ class VerificationTest {
|
|||
fun bound_variable_to_compound_term_is_compound() {
|
||||
val variable = Variable("X")
|
||||
val structure = Structure(Atom("a"), listOf(Atom("b")))
|
||||
variable.bind(structure)
|
||||
assertTrue(compound(variable))
|
||||
assertTrue(compound(variable, mapOf(variable to structure)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -221,13 +207,12 @@ class VerificationTest {
|
|||
val variable2 = Variable("Y")
|
||||
val structure = Structure(Atom("a"), listOf(Atom("b")))
|
||||
|
||||
variable2.bind(structure)
|
||||
variable1.bind(variable2)
|
||||
val subs: Substitutions = mapOf(
|
||||
variable1 to variable2,
|
||||
variable2 to structure
|
||||
)
|
||||
|
||||
assertTrue(compound(variable1))
|
||||
|
||||
assertEquals(structure, variable2.alias().get())
|
||||
assertEquals(variable2, variable1.alias().get())
|
||||
assertTrue(compound(variable1, subs))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
|||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.RepeatedTest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.terms.Integer
|
||||
import prolog.ast.terms.Term
|
||||
import prolog.ast.terms.Variable
|
||||
|
@ -15,7 +15,11 @@ class ArithmeticTests {
|
|||
val result = between(Integer(0), Integer(2), Integer(1))
|
||||
|
||||
assertTrue(result.any(), "Expected 1 to be between 0 and 2")
|
||||
assertEquals(emptyMap<Variable, Term>(), result.first(), "Expected no substitutions")
|
||||
assertTrue(result.first().isSuccess, "Expected success")
|
||||
|
||||
val subs = result.first().getOrNull()!!
|
||||
|
||||
assertEquals(emptyMap<Variable, Term>(), subs, "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -39,9 +43,11 @@ class ArithmeticTests {
|
|||
assertEquals(expectedResults.size, actualResults.size, "Expected 3 results")
|
||||
for ((expected, actual) in expectedResults.zip(actualResults)) {
|
||||
for ((key, value) in expected) {
|
||||
assertTrue(actual.isSuccess, "Expected success")
|
||||
val actual = actual.getOrNull()!!
|
||||
assertTrue(actual.containsKey(key), "Expected key $key to be present")
|
||||
assertTrue(
|
||||
equivalent(value, actual[key]!!),
|
||||
equivalent(value, actual[key]!!, emptyMap()),
|
||||
"Expected value $value for key $key, but got ${actual[key]}"
|
||||
)
|
||||
}
|
||||
|
@ -93,20 +99,6 @@ class ArithmeticTests {
|
|||
val t1 = Variable("X")
|
||||
val t2 = Integer(2)
|
||||
|
||||
t1.bind(Integer(1))
|
||||
|
||||
val result = succ(t1, t2, emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected X + 1 to be equal to 2")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `succ(bound-to-1-var) is 2 by map`() {
|
||||
val t1 = Variable("X")
|
||||
val t2 = Integer(2)
|
||||
|
||||
val result = succ(t1, t2, mapOf(t1 to Integer(1))).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected X + 1 to be equal to 2")
|
||||
|
@ -119,20 +111,6 @@ class ArithmeticTests {
|
|||
val t1 = Variable("X")
|
||||
val t2 = Variable("Y")
|
||||
|
||||
t1.bind(Integer(1))
|
||||
|
||||
val result = succ(t1, t2, emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected X + 1 to be equal to Y")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
assertEquals(Integer(2), result[0].getOrNull()!![t2], "Expected Y to be equal to 2")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `succ(bound-to-1-var) is var by map`() {
|
||||
val t1 = Variable("X")
|
||||
val t2 = Variable("Y")
|
||||
|
||||
val result = succ(t1, t2, mapOf(t1 to Integer(1))).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected X + 1 to be equal to Y")
|
||||
|
@ -219,21 +197,6 @@ class ArithmeticTests {
|
|||
val t2 = Integer(2)
|
||||
val t3 = Variable("X")
|
||||
|
||||
t3.bind(Integer(3))
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "1 + 2 should be equal to X")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
assertTrue(result[0].getOrNull()!!.isEmpty(), "t3 should not be rebound")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `1 plus 2 is bound-to-3-var by map`() {
|
||||
val t1 = Integer(1)
|
||||
val t2 = Integer(2)
|
||||
val t3 = Variable("X")
|
||||
|
||||
val result = plus(t1, t2, t3, mapOf(Variable("X") to Integer(3))).toList()
|
||||
|
||||
assertEquals(1, result.size, "1 + 2 should be equal to X")
|
||||
|
@ -247,9 +210,7 @@ class ArithmeticTests {
|
|||
val t2 = Integer(2)
|
||||
val t3 = Variable("X")
|
||||
|
||||
t3.bind(Integer(4))
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap())
|
||||
val result = plus(t1, t2, t3, mapOf(t3 to Integer(4)))
|
||||
|
||||
assertTrue(result.none(), "1 + 2 should not be equal to X")
|
||||
}
|
||||
|
@ -260,9 +221,7 @@ class ArithmeticTests {
|
|||
val t2 = Variable("X")
|
||||
val t3 = Integer(3)
|
||||
|
||||
t2.bind(Integer(2))
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||
val result = plus(t1, t2, t3, mapOf(t2 to Integer(2))).toList()
|
||||
|
||||
assertEquals(1, result.size, "1 + X should be equal to 3")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
|
@ -275,9 +234,7 @@ class ArithmeticTests {
|
|||
val t2 = Variable("X")
|
||||
val t3 = Integer(4)
|
||||
|
||||
t2.bind(Integer(2))
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap())
|
||||
val result = plus(t1, t2, t3, mapOf(t2 to Integer(2)))
|
||||
|
||||
assertTrue(result.none(), "1 + X should not be equal to 4")
|
||||
}
|
||||
|
@ -288,9 +245,7 @@ class ArithmeticTests {
|
|||
val t2 = Integer(2)
|
||||
val t3 = Integer(3)
|
||||
|
||||
t1.bind(Integer(1))
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||
val result = plus(t1, t2, t3, mapOf(t1 to Integer(1))).toList()
|
||||
|
||||
assertEquals(1, result.size, "X + 2 should be equal to 3")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
|
@ -303,9 +258,7 @@ class ArithmeticTests {
|
|||
val t2 = Integer(2)
|
||||
val t3 = Integer(4)
|
||||
|
||||
t1.bind(Integer(1))
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap())
|
||||
val result = plus(t1, t2, t3, mapOf(t1 to Integer(1)))
|
||||
|
||||
assertTrue(result.none(), "X + 2 should not be equal to 4")
|
||||
}
|
||||
|
@ -329,14 +282,16 @@ class ArithmeticTests {
|
|||
val t2 = Variable("Y")
|
||||
val t3 = Variable("Z")
|
||||
|
||||
t1.bind(Integer(1))
|
||||
t2.bind(Integer(2))
|
||||
val map: Substitutions = mapOf(
|
||||
t1 to Integer(1),
|
||||
t2 to Integer(2),
|
||||
)
|
||||
|
||||
val result = plus(t1, t2, t3, emptyMap()).toList()
|
||||
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]!!, Integer(3)), "Z should be equal to 3")
|
||||
assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Integer(3), result[0].getOrNull()!!), "Z should be equal to 3")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -3,10 +3,12 @@ package prolog.logic
|
|||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.terms.Integer
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Variable
|
||||
import prolog.builtins.Add
|
||||
|
||||
/*
|
||||
* Based on: https://en.wikipedia.org/wiki/Unification_%28computer_science%29#Examples_of_syntactic_unification_of_first-order_terms
|
||||
|
@ -19,8 +21,8 @@ class UnifyTest {
|
|||
|
||||
val result = unify(atom1, atom2)
|
||||
|
||||
assertTrue(result.isPresent, "Identical atoms should unify")
|
||||
assertEquals(0, result.get().size, "No substitutions should be made")
|
||||
assertTrue(result.isSuccess, "Identical atoms should unify")
|
||||
assertEquals(0, result.getOrNull()!!.size, "No substitutions should be made")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -30,7 +32,7 @@ class UnifyTest {
|
|||
|
||||
val result = unify(atom1, atom2)
|
||||
|
||||
assertFalse(result.isPresent, "Different atoms should not unify")
|
||||
assertFalse(result.isSuccess, "Different atoms should not unify")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,8 +46,8 @@ class UnifyTest {
|
|||
|
||||
val result = unify(variable1, variable2)
|
||||
|
||||
assertTrue(result.isPresent, "Identical variables should unify")
|
||||
assertEquals(0, result.get().size, "No substitutions should be made")
|
||||
assertTrue(result.isSuccess, "Identical variables should unify")
|
||||
assertEquals(0, result.getOrNull()!!.size, "No substitutions should be made")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -55,9 +57,9 @@ class UnifyTest {
|
|||
|
||||
val result = unify(atom, variable)
|
||||
|
||||
assertTrue(result.isPresent, "Variable should unify with atom")
|
||||
assertEquals(1, result.get().size, "There should be one substitution")
|
||||
assertEquals(atom, variable.alias().get(), "Variable should be substituted with atom")
|
||||
assertTrue(result.isSuccess, "Variable should unify with atom")
|
||||
assertEquals(1, result.getOrNull()!!.size, "There should be one substitution")
|
||||
assertEquals(atom, result.getOrNull()!![variable], "Variable should be substituted with atom")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -67,9 +69,9 @@ class UnifyTest {
|
|||
|
||||
val result = unify(variable1, variable2)
|
||||
|
||||
assertTrue(result.isPresent)
|
||||
assertEquals(1, result.get().size)
|
||||
assertEquals(variable2, variable1.alias().get(), "Variable 1 should alias to variable 2")
|
||||
assertTrue(result.isSuccess)
|
||||
assertEquals(1, result.getOrNull()!!.size)
|
||||
assertEquals(variable2, result.getOrNull()!![variable1], "Variable 1 should alias to variable 2")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -79,8 +81,8 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertTrue(result.isPresent, "Identical compound terms should unify")
|
||||
assertEquals(0, result.get().size, "No substitutions should be made")
|
||||
assertTrue(result.isSuccess, "Identical compound terms should unify")
|
||||
assertEquals(0, result.getOrNull()!!.size, "No substitutions should be made")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -90,7 +92,7 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertFalse(result.isPresent, "Different compound terms should not unify")
|
||||
assertFalse(result.isSuccess, "Different compound terms should not unify")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -100,7 +102,7 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertFalse(result.isPresent, "Compound terms with different functors should not unify")
|
||||
assertFalse(result.isSuccess, "Compound terms with different functors should not unify")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,10 +116,14 @@ class UnifyTest {
|
|||
|
||||
val result = unify(variable, structure)
|
||||
|
||||
assertTrue(result.isPresent, "Variable should unify with compound term")
|
||||
assertEquals(1, result.get().size, "There should be one substitution")
|
||||
assertTrue(result.isSuccess, "Variable should unify with compound term")
|
||||
|
||||
val subs = result.getOrNull()!!
|
||||
|
||||
assertEquals(1, subs.size, "There should be one substitution")
|
||||
assertTrue(subs.containsKey(variable), "Variable should be in the substitution map")
|
||||
assertTrue(
|
||||
equivalent(Structure(Atom("f"), listOf(Atom("a"), Atom("b"))), variable.alias().get()),
|
||||
equivalent(Structure(Atom("f"), listOf(Atom("a"), Atom("b"))), subs[variable]!!, subs),
|
||||
"Variable should be substituted with compound term"
|
||||
)
|
||||
}
|
||||
|
@ -130,9 +136,13 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertTrue(result.isPresent, "Compound term with variable should unify with part")
|
||||
assertEquals(1, result.get().size, "There should be one substitution")
|
||||
val equivalence = equivalent(Atom("b"), variable.alias().get())
|
||||
assertTrue(result.isSuccess, "Compound term with variable should unify with part")
|
||||
|
||||
val subs = result.getOrNull()!!
|
||||
|
||||
assertEquals(1, subs.size, "There should be one substitution")
|
||||
assertTrue(subs.containsKey(variable), "Variable should be in the substitution map")
|
||||
val equivalence = equivalent(Atom("b"), subs[variable]!!, subs)
|
||||
assertTrue(equivalence, "Variable should be substituted with atom")
|
||||
}
|
||||
|
||||
|
@ -146,9 +156,13 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertTrue(result.isPresent, "Compound terms with variable arguments should unify")
|
||||
assertEquals(1, result.get().size, "There should be one substitution")
|
||||
assertEquals(variable2, variable1.alias().get(), "Variable 1 should alias to variable 2")
|
||||
assertTrue(result.isSuccess, "Compound terms with variable arguments should unify")
|
||||
|
||||
val subs = result.getOrNull()!!
|
||||
|
||||
assertEquals(1, subs.size, "There should be one substitution")
|
||||
assertTrue(subs.containsKey(variable1), "Variable 1 should be in the substitution map")
|
||||
assertEquals(variable2, subs[variable1], "Variable 1 should alias to variable 2")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,7 +175,7 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertFalse(result.isPresent, "Compound terms with different arity should not unify")
|
||||
assertFalse(result.isSuccess, "Compound terms with different arity should not unify")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,10 +191,14 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertTrue(result.isPresent, "Nested compound terms with variables should unify")
|
||||
assertEquals(1, result.get().size, "There should be one substitution")
|
||||
assertTrue(result.isSuccess, "Nested compound terms with variables should unify")
|
||||
|
||||
val subs = result.getOrNull()!!
|
||||
|
||||
assertEquals(1, subs.size, "There should be one substitution")
|
||||
assertTrue(subs.containsKey(variable2), "Variable 2 should be in the substitution map")
|
||||
assertTrue(
|
||||
equivalent(Structure(Atom("g"), listOf(Variable("X"))), variable2.alias().get()),
|
||||
equivalent(Structure(Atom("g"), listOf(Variable("X"))), subs[variable2]!!, subs),
|
||||
"Variable should be substituted with compound term"
|
||||
)
|
||||
}
|
||||
|
@ -200,15 +218,22 @@ class UnifyTest {
|
|||
|
||||
val result = unify(structure1, structure2)
|
||||
|
||||
assertTrue(result.isPresent, "Compound terms with more variables should unify")
|
||||
assertEquals(2, result.get().size, "There should be two substitutions")
|
||||
assertTrue(result.isSuccess, "Compound terms with more variables should unify")
|
||||
|
||||
val subs = result.getOrNull()!!
|
||||
|
||||
assertEquals(2, subs.size, "There should be two substitutions")
|
||||
assertTrue(subs.containsKey(variable1), "Variable 1 should be in the substitution map")
|
||||
assertTrue(
|
||||
equivalent(Atom("a"), variable1.alias().get()),
|
||||
equivalent(Atom("a"), subs[variable1]!!, subs),
|
||||
"Variable 1 should be substituted with atom"
|
||||
)
|
||||
val equivalence = equivalent(Structure(Atom("g"), listOf(Atom("a"))), variable2.alias().get())
|
||||
assertTrue(equivalence, "Variable 2 should be substituted with compound term")
|
||||
assertTrue(subs.containsKey(variable2), "Variable 2 should be in the substitution map")
|
||||
assertTrue(
|
||||
equivalent(Structure(Atom("g"), listOf(Atom("a"))), subs[variable2]!!, subs),
|
||||
"Variable 2 should be substituted with compound term"
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,11 +245,16 @@ class UnifyTest {
|
|||
val variable1 = Variable("X")
|
||||
val structure2 = Structure(Atom("f"), listOf(Variable("X")))
|
||||
|
||||
val result = unify(variable1, structure2)
|
||||
val result = unifyLazy(variable1, structure2, emptyMap()).toList()
|
||||
|
||||
assertTrue(result.isPresent, "Recursive unification should succeed")
|
||||
assertEquals(1, result.get().size, "There should be one substitution")
|
||||
assertEquals(structure2, variable1.alias().get(), "Variable should be substituted with compound term")
|
||||
assertEquals(1, result.size, "There should be one result")
|
||||
assertTrue(result[0].isSuccess, "Recursive unification should succeed")
|
||||
|
||||
val subs = result[0].getOrNull()!!
|
||||
|
||||
assertEquals(1, subs.size, "There should be one substitution")
|
||||
assertTrue(subs.containsKey(variable1), "Variable should be in the substitution map")
|
||||
assertEquals(structure2, subs[variable1], "Variable should be substituted with compound term")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,13 +268,15 @@ class UnifyTest {
|
|||
val variable2 = Variable("Y")
|
||||
val atom = Atom("bar")
|
||||
|
||||
variable1.bind(atom)
|
||||
variable2.bind(atom)
|
||||
val map: Substitutions = mapOf(
|
||||
variable1 to atom,
|
||||
variable2 to atom
|
||||
)
|
||||
val result = unifyLazy(variable1, variable2, map).toList()
|
||||
|
||||
val result = unify(variable1, variable2)
|
||||
|
||||
assertTrue(result.isPresent, "Multiple unification should succeed")
|
||||
assertEquals(0, result.get().size, "No substitutions should be made")
|
||||
assertEquals(1, result.size, "There should be one substitution")
|
||||
assertTrue(result[0].isSuccess, "Multiple unification should succeed")
|
||||
assertEquals(0, result[0].getOrNull()!!.size, "No (additional) substitutions should be made")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +290,7 @@ class UnifyTest {
|
|||
|
||||
val result = unify(atom1, structure2)
|
||||
|
||||
assertFalse(result.isPresent, "Atom with different arity should not unify")
|
||||
assertFalse(result.isSuccess, "Atom with different arity should not unify")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -268,8 +300,8 @@ class UnifyTest {
|
|||
|
||||
val result = unify(int1, int2)
|
||||
|
||||
assertTrue(result.isPresent, "Identical integers should unify")
|
||||
assertEquals(0, result.get().size, "No substitutions should be made")
|
||||
assertTrue(result.isSuccess, "Identical integers should unify")
|
||||
assertEquals(0, result.getOrNull()!!.size, "No substitutions should be made")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -279,6 +311,17 @@ class UnifyTest {
|
|||
|
||||
val result = unify(int1, int2)
|
||||
|
||||
assertFalse(result.isPresent, "Different integers should not unify")
|
||||
assertFalse(result.isSuccess, "Different integers should not unify")
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `1 + 2 does not unify with 3`() {
|
||||
val expr1 = Add(Integer(1), Integer(2))
|
||||
val expr2 = Integer(3)
|
||||
|
||||
val result = unify(expr1, expr2)
|
||||
|
||||
assertFalse(result.isSuccess, "1 + 2 should not unify with 3")
|
||||
}
|
||||
}
|
Reference in a new issue