refactor: Rework
This commit is contained in:
parent
ac55ed4c64
commit
6469dd6ced
34 changed files with 593 additions and 552 deletions
|
@ -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