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

@ -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

View file

@ -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")
}
}