You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.0 KiB
Kotlin
105 lines
3.0 KiB
Kotlin
package net.cijber.pubgrub
|
|
|
|
import net.cijber.pubgrub.packages.PackageSelection
|
|
import net.cijber.pubgrub.stubs.PackageId
|
|
import net.cijber.pubgrub.stubs.Version
|
|
|
|
class PartialSolution<P : PackageId, V : Version<V>> {
|
|
private var decisionLevel = 0
|
|
private val assignments = mutableListOf<Assignment<P, V>>()
|
|
private var backtracking = false
|
|
|
|
private val decisions = mutableListOf<Assignment<P, V>>()
|
|
|
|
private val positive = mutableMapOf<P, Term<P, V>>()
|
|
private val negative = mutableMapOf<P, Term<P, V>>()
|
|
|
|
infix fun relation(term: Term<P, V>): SetRelation {
|
|
positive.get(term.pkg)?.let {
|
|
return it relation term
|
|
}
|
|
|
|
negative.get(term.pkg)?.let {
|
|
return it relation term
|
|
}
|
|
|
|
return SetRelation.Overlaps
|
|
}
|
|
|
|
fun derive(pkg: PackageSelection<P, V>, exclusive: Boolean, incompatibility: Incompatibility<P, V>) {
|
|
assign(Assignment(pkg, !exclusive, incompatibility, decisionLevel, assignments.count()))
|
|
}
|
|
|
|
private fun assign(assignment: Assignment<P, V>) {
|
|
assignments.add(assignment)
|
|
register(assignment)
|
|
}
|
|
|
|
private fun register(assignment: Assignment<P, V>) {
|
|
val pkg = assignment.pkg
|
|
val oldPositive = positive[pkg]
|
|
if (oldPositive != null) {
|
|
positive.remove(pkg)
|
|
oldPositive.intersect(assignment)?.let {
|
|
positive[pkg] = it
|
|
}
|
|
}
|
|
|
|
val oldNegative = negative[pkg]
|
|
val term = if (oldNegative == null) {
|
|
assignment
|
|
} else {
|
|
assignment.intersect(oldNegative)!!
|
|
}
|
|
|
|
if (!term.exclusive) {
|
|
negative.remove(pkg)
|
|
positive[pkg] = term
|
|
} else {
|
|
negative[pkg] = term
|
|
}
|
|
}
|
|
|
|
fun satisfier(term: Term<P, V>): Assignment<P, V> {
|
|
var assignedTerm: Term<P, V>? = null;
|
|
for (assignment in assignments) {
|
|
if (assignment.pkg != term.pkg) continue
|
|
|
|
assignedTerm = if (assignedTerm == null) {
|
|
assignment
|
|
} else {
|
|
assignedTerm.intersect(assignment)
|
|
}
|
|
|
|
if (assignedTerm?.satisfies(term) == true) {
|
|
return assignment
|
|
}
|
|
}
|
|
|
|
error("[BUG] $term is not satisfied")
|
|
}
|
|
|
|
fun backtrack(decisionLevel: Int) {
|
|
backtracking = true
|
|
val packages = mutableSetOf<P>()
|
|
while (assignments.lastOrNull()?.decisionLevel?.let { it > decisionLevel } == true) {
|
|
val removed = assignments.removeAt(assignments.lastIndex)
|
|
packages.add(removed.pkg)
|
|
|
|
if (removed.isDecision) {
|
|
decisions.remove(removed)
|
|
}
|
|
}
|
|
|
|
for (pkg in packages) {
|
|
positive.remove(pkg)
|
|
negative.remove(pkg)
|
|
}
|
|
|
|
for (assignment in assignments) {
|
|
if (packages.contains(assignment.pkg)) {
|
|
register(assignment)
|
|
}
|
|
}
|
|
}
|
|
} |