Skip to content

Commit 0bcd119

Browse files
committed
WIP: Implement unifier
1 parent 6b5a14a commit 0bcd119

File tree

4 files changed

+154
-2
lines changed

4 files changed

+154
-2
lines changed

disjointmap/src/main/kotlin/net/pelsmaeker/collections/DisjointMapImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,7 @@ internal fun <K, V> DisjointMap<K, V>.toMapImpl(
245245
return mapping.map { (rep, keys) ->
246246
@Suppress("UNCHECKED_CAST")
247247
keys.toPersistentSet() to (roots[rep] as V)
248-
}
249-
.toMap<Set<K>, V>()
248+
}.toMap<Set<K>, V>()
250249
}
251250

252251
// TODO: Replace this function with Map.replaceAll() once it's fixed for PersistentMap.builder()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package net.pelsmaeker.unifiers
2+
3+
internal class UnifyOperation<T, V: T> {
4+
/** The queue of pairs of terms to unify. */
5+
private val worklist: ArrayDeque<Pair<T, T>> = ArrayDeque<Pair<T, T>>()
6+
7+
constructor(left: T, right: T) {
8+
worklist.add(Pair(left, right))
9+
}
10+
11+
constructor(pairs: Iterable<Pair<T, T>>) {
12+
worklist.addAll(pairs)
13+
}
14+
15+
constructor(unifier: Unifier<T, V>) {
16+
TODO()
17+
}
18+
19+
20+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package net.pelsmaeker.unifiers
2+
3+
import net.pelsmaeker.collections.MutableDisjointMap
4+
import net.pelsmaeker.collections.MutableUnionFindMap
5+
6+
abstract class UnionFindUnifier<T, V: T>: MutableUnifier<T, V> {
7+
private val unionFind: MutableDisjointMap<V, T> = MutableUnionFindMap()
8+
9+
override fun composeWith(other: Unifier<T, V>): Boolean {
10+
TODO("Not yet implemented")
11+
}
12+
13+
override fun add(v: V, term: T): Boolean {
14+
TODO("Not yet implemented")
15+
}
16+
17+
override fun addAll(map: Map<V, T>): Boolean {
18+
TODO()
19+
}
20+
21+
override fun unify(term1: T, term2: T): Boolean {
22+
TODO("Not yet implemented")
23+
}
24+
25+
override fun isEmpty(): Boolean = unionFind.isEmpty()
26+
27+
override fun find(v: V): V? = unionFind.find(v)
28+
29+
override fun get(term: T): T {
30+
val v = asVar(term) ?: return term
31+
return unionFind.getOrDefault(v, v)
32+
}
33+
34+
override fun same(term1: T, term2: T): Boolean {
35+
return term1 == term2
36+
|| unionFind.same(asVar(term1) ?: return false, asVar(term2) ?: return false)
37+
}
38+
39+
override fun instantiate(term: T): T {
40+
val t = asVar(term)?.let { unionFind[it] ?: return it } ?: term
41+
val newSubterms = getSubterms(t).map { instantiate(it) }
42+
return withSubterms(t, newSubterms)
43+
}
44+
45+
override fun getFreeVars(term: T): Set<V> {
46+
val t = asVar(term)?.let { unionFind[it] ?: return setOf(it) } ?: term
47+
val freeVars = getSubterms(t).map { getFreeVars(it) }
48+
return freeVars.fold(setOf()) { acc, set -> acc + set }
49+
}
50+
51+
override fun isGround(term: T): Boolean = getFreeVars(term).isEmpty()
52+
53+
override fun isCyclic(term: T): Boolean {
54+
TODO()
55+
}
56+
57+
override fun equals(other: Any?): Boolean {
58+
if (other is UnionFindUnifier<*, *>) {
59+
return this.unionFind == other.unionFind
60+
} else if (other is MutableUnifier<*, *>) {
61+
TODO()
62+
}
63+
return super.equals(other)
64+
}
65+
66+
override fun hashCode(): Int {
67+
return this.unionFind.hashCode()
68+
}
69+
70+
/**
71+
* Returns the given term as a variable, if it is one.
72+
*
73+
* @param term The term to check.
74+
* @return The term as a variable, or `null` if the term is not a variable.
75+
*/
76+
protected abstract fun asVar(term: T): V?
77+
78+
/**
79+
* Determines whether the two terms are equal, ignoring their subterms.
80+
*
81+
* @param term1 The first term.
82+
* @param term2 The second term.
83+
* @return `true` if the two terms are equal, ignoring their subterms; otherwise, `false`.
84+
*/
85+
protected abstract fun isEqualWithoutSubterms(term1: T, term2: T): Boolean
86+
87+
/**
88+
* Gets the subterms of the given term.
89+
*
90+
* @param term The term for which to get the subterms.
91+
* @return The subterms of the term.
92+
*/
93+
protected abstract fun getSubterms(term: T): List<T>
94+
95+
/**
96+
* Creates a new term with the given subterms.
97+
*
98+
* @param term The term to copy.
99+
* @param subterms The subterms to use.
100+
* @return The new term with the given subterms.
101+
*/
102+
protected abstract fun withSubterms(term: T, subterms: List<T>): T
103+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package net.pelsmaeker.unifiers
2+
3+
import io.kotest.core.spec.style.FunSpec
4+
5+
class UnionFindUnifierTests: FunSpec({
6+
include(testUnifier { map ->
7+
TermUnionFindUnifier().apply { addAll(map) }
8+
})
9+
10+
include(testMutableUnifier { map ->
11+
TermUnionFindUnifier().apply { addAll(map) }
12+
})
13+
})
14+
15+
class TermUnionFindUnifier : UnionFindUnifier<Term, TermVar>() {
16+
override fun asVar(term: Term): TermVar? = term as? TermVar
17+
override fun isEqualWithoutSubterms(
18+
term1: Term,
19+
term2: Term,
20+
): Boolean {
21+
TODO("Not yet implemented")
22+
}
23+
24+
override fun withSubterms(term: Term, subterms: List<Term>): Term = when(term) {
25+
is ApplTerm -> term.copy(args = subterms)
26+
is ListTerm -> term.copy(elements = subterms)
27+
else -> term
28+
}
29+
override fun getSubterms(term: Term): List<Term> = term.subterms
30+
}

0 commit comments

Comments
 (0)