com.jtransc.util.explore.kt Maven / Gradle / Ivy
/*
* Copyright 2016 Carlos Ballesteros Velasco
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jtransc.util
import com.jtransc.ds.Queue
import com.jtransc.error.InvalidOperationException
import java.util.*
fun recursiveExploration(initialItems: Set, performExploration: (item: T) -> Iterable): Set {
return recursiveExploration(initialItems, null, performExploration)
}
fun recursiveExploration(initialItems: Set, extra: ((item:T) -> Iterable)?, performExploration: (item: T) -> Iterable): Set {
val explored = HashSet(initialItems)
val toExploreList = Queue(initialItems)
fun explore(item: T?) {
if (item != null && item !in explored) {
explored.add(item)
toExploreList.queue(item)
}
}
do {
while (toExploreList.hasMore) {
val toExplore = toExploreList.dequeue()
for (item in performExploration(toExplore)) explore(item)
}
if (extra != null) {
explored.toList().forEach {
extra(it).forEach {
explore(it)
}
}
}
} while (toExploreList.hasMore)
return explored
}
fun List.dependencySorter(allowCycles:Boolean = false, getDependencies: (item:T) -> List):List {
return this.dependencySorterOld(allowCycles, getDependencies)
}
// @TODO: Optimize this
// This could construct a tree with a root node all items depend on.
// We should remove items that depend on root but also depends on other stuff.
// Later we should iterate the tree from leafs to root. This should be order
// of magnitudes faster with lots of items.
fun List.dependencySorterOld(allowCycles:Boolean = false, getDependencies: (item:T) -> List):List {
val all = this
val usages = LinkedHashMap>()
val dependencies = LinkedHashMap>()
for (it in all) usages[it] = arrayListOf()
for (it in all) {
val deps = getDependencies(it).toSet() - it
dependencies[it] = deps.toCollection(arrayListOf())
for (dep in deps) usages[dep]?.add(it)
}
// @TODO: Optimize this
val out = arrayListOf()
while (usages.isNotEmpty()) {
//println("Usages:" + usages.size)
//val emptyItem = usages.entries.firstOrNull { it.value.isEmpty() } ?: usages.entries.first()
val emptyItem = if (allowCycles) {
usages.entries.firstOrNull { it.value.isEmpty() } ?: usages.entries.first()
} else {
usages.entries.firstOrNull { it.value.isEmpty() } ?: throw InvalidOperationException("Cycle detected!")
}
val item = emptyItem.key
usages.remove(item)
for (a in dependencies[item]!!) {
usages[a]?.remove(item)
}
out.add(item)
//println(item)
}
return out.reversed()
}
fun sortDependenciesSimple(entry:T, getDependencies: (item:T) -> List):List {
var out = arrayListOf()
fun step(item:T, used:MutableSet = hashSetOf()) {
if (item in used) return
used.add(item)
for (dep in getDependencies(item)) step(dep, used)
out.add(item)
}
step(entry)
return out
}