hi, i have wasted an embarrassing amount of time t...
# announcements
j
hi, i have wasted an embarrassing amount of time trying to fit
fold
, or
reduce
to this, finally, i just did it as a while loop. is there a one-liner for this ?
Copy code
var acc = sim.outputRange.indices
        val tree = sortedSetOf<Int>()
        while (acc.isNotEmpty()) {
            tree += acc;
              acc = acc.map { this.usefulScope(it) }.flatten().filter {
                it in sim.hiddenRange } - tree
        }
e
not quite one line, but something like this may be equivalent:
Copy code
val tree = sortedSetOf<Int>()
generateSequence(sim.outputRange.indices) { acc ->
    acc.flatMap { usefulScope(it) }.filter { it in sim.hiddenRange && it !in tree }.ifEmpty { null }
}.flatMapTo(tree) { it }
p
not sure if it’s right since your code sample is not compilable and missing some information:
Copy code
sim.outputRange.indices
  .mapNotNull(this::usefulScope)
  .intersect(sim.hiddenRange)
  .minus(tree)
  .toSortedSet()
e
@Peter Ertl I don't think that's right since the original is looping, so it is something like
sim.outputRange.indices + sim.outputRange.indices.flatMap(::usefulScope) + sim.outputRange.indices.flatMap(::usefulScope).flatMap(::usefulScope) + ...
j
its kinda a recursive problem, or a fold/reduce problem, but nothing quite fits.
p
Give us a working sample so we can try to optimize it
✔️ 1
e
Copy code
val queue = ArrayDeque(sim.outputRange.indices)
val tree = sortedSetOf<Int>()
generateSequence(queue::removeFirstOrNull).filter(tree::add).flatMapTo(queue) { usefulScope(it) intersect sim.hiddenRange }
r
it's basically some kind of simple search over <something> that
usefulScope
does Imho I wouldn't try to do it as one liner, I would just do a generic
search
function, that takes a starting point(s) and a
neighborhoods
function (takes a point, and returns all nearby) this way you can separate the concepts of what exactly it does: both simple search & neighborhoods will be easy to understand, in fact the last @ephemient's example is pretty close to this Something like this:
Copy code
fun <T> breadthFirstSearch(start: Collection<T>, neighborhoods: (T) -> Collection<T>): Sequence<T> {
    val queue = ArrayDeque(start)
    return generateSequence(queue::removeFirstOrNull)
        .distinct()
        .onEach { queue.addAll(neighborhoods(it)) }
}

breadthFirstSearch(sim.outputRange.indices) { current -> 
    usefulScope(current) intersect sim.hiddenRange
}
good thing about it is, that you separate what you search, from how you search it
e
I wonder if it's better to use Sequence.distinct().toSortedSet(), or Sequence.filter(SortedSet::add), since that seemed to be the desired result... but yeah, this is exactly what a BFS is
if traversal order doesn't matter, DFS would work as well:
Copy code
val tree = sortedSetOf<Int>()
val search = DeepRecursiveFunction<Int, Unit> { if (tree.add(it)) (usefulScope(it) intersect sim.hiddenRange).forEach(::callRecursive) }
sim.outputRange.indices.forEach(search::invoke)
🚀 1
j
by request, here's the code in a working tree with no external deps. https://gitlab.com/fjLWN2z5O1/bfneat/-/blob/clean_deps/src/main/java/pairwise/idiom/neat/Gnome.kt#L36
there's a gene living in a genome that cannot assign itself an index in the parent, so the parent must apply the outer context to print a meaningful pruned list of links working backward from the outputs.
@ephemient i didn't even notice when DeepRecursiveFunction was added to stdlib. your proposal works like a charm!
the system populates all genes and they exist soaking up mutations whether they are in the output solution or not. below nodes 14..18 are pruned out, e.g. outside of "useful"
Copy code
Gnome(points=0.9999116613481498, jeans=[(2, Jean(gated=false, af=ExponentialLinearFunction, impulse=1.0, inputs=[0, 1], weights=[1.0, 0.76])), (3, Jean(gated=false, af=EvSailSigmoid, impulse=0.0, inputs=[0, 1], weights=[-1.0, 0.46])), (4, Jean(gated=false, af=SqrtAndLinear, impulse=1.0, inputs=[0, 1], weights=[1.0, 0.99])), (5, Jean(gated=false, af=SignedClampedLinear, impulse=2.0, inputs=[0, 1, 2], weights=[1.0, 1.0, 1.0])), (6, Jean(gated=false, af=ExponentialLinearFunction, impulse=2.5, inputs=[0, 1, 3, 4], weights=[1.0, 0.76, 1.0, 1.0])), (7, Jean(gated=false, af=Linear, impulse=1.0, inputs=[0, 1, 4], weights=[1.0, 1.0, 1.0])), (8, Jean(gated=false, af=Absolute, impulse=2.820130884406553, inputs=[0, 1, 2, 7], weights=[0.82, 1.0, 1.0, 1.0])), (9, Jean(gated=false, af=ConvertToSigned, impulse=4.820130884406553, inputs=[0, 1, 5, 8], weights=[1.0, 0.36, 1.0, 1.0])), (10, Jean(gated=false, af=BipolarSigmoid, impulse=7.200927962384435, inputs=[0, 1, 3, 4, 5, 7, 8, 9], weights=[0.36, 1.0, 0.76, 1.0, 1.0, 1.0, 1.0, 1.0])), (11, Jean(gated=false, af=Sine, impulse=2.48750260912872, inputs=[0, 1, 2, 7, 8], weights=[1.0, 1.0, 0.76, 0.68, 0.36])), (12, Jean(gated=false, af=Recipriocal, impulse=9.652278437785709, inputs=[0, 1, 3, 4, 6, 7, 8, 9, 10, 11], weights=[1.0, 1.0, 1.0, 0.76, 1.0, 1.0, 1.0, 0.46, 1.0, 1.0])), (13, Jean(gated=false, af=SteepSigmoid, impulse=2.6267907935893584, inputs=[0, 1, 2, 5, 7, 8, 12], weights=[0.0, 0.97, 0.76, 0.76, 1.0, 0.0, 1.0])), (19, Jean(gated=false, af=Linear, impulse=1.0002208466296254, inputs=[0, 1, 8, 11, 13], weights=[0.22, 0.21, 0.05, 0.69, 0.21]))]}