Skip to content

DynamicGraphSystemsExample.kt

src/jvmMain/kotlin/afield/examples/stdlib/DynamicGraphSystemsExample.kt · 144 lines

package afield.examples.stdlib

import afield.data.graph.DynamicEdgeList
import afield.data.graph.DynamicGraphSystem
import afield.data.graph.DynamicPointState
import afield.data.graph.GraphPathSetResult
import afield.data.graph.PointGraph
import afield.math.linalg.Vec3
import afield.data.graph.Vec3AlphaEventHypergraphCollapseSystem
import afield.data.graph.Vec3BreathingAnisotropicKnnSystem
import afield.data.graph.Vec3FlowlineAdvectionGraphSystem
import afield.data.graph.Vec3LocalTangentTriangulationSystem
import afield.data.graph.Vec3PersistentProximityHysteresisSystem
import afield.data.graph.Vec3SignalRoutingGraphSystem
import afield.data.graph.Vec3SpatialHash
import afield.math.linalg.Vec4
import afield.data.graph.graphAnchoredGreedyThenDiameterCover
import afield.data.graph.stepDynamicGraphWithExponentialDecay

fun dynamicStateOf

Helper to convert external data into the dynamic graph state used by the examples.

fun dynamicStateOf(
    points: List<Vec3>,
    labels: List<Vec4>? = null,
    time: Float = 0f
): DynamicPointState = DynamicPointState(points.toMutableList(), labels, time)

fun exampleDynamicGraphPipeline

Example: use a dynamic graph system, then snapshot into PointGraph so existing traversal / cover / diameter / A* code can operate unchanged.

fun exampleDynamicGraphPipeline(
    points: List<Vec3>,
    labels: List<Vec4>? = null
): PointGraph {
    val state = dynamicStateOf(points, labels)
    val edges = DynamicEdgeList(pointCount = state.pointCount, undirected = true)
    val spatialHash = Vec3SpatialHash(cellSize = 0.15)

    val system: DynamicGraphSystem = Vec3FlowlineAdvectionGraphSystem(
        influenceRadius = 0.25,
        stepLength = 0.12,
        ttl = 2.0f,
        reinforce = 1.2,
        maxWeight = 8.0,
        swirlMix = 0.45
    )

    val dt = 1f / 60f
    repeat(60) {
        stepDynamicGraphWithExponentialDecay(
            dt = dt,
            state = state,
            edges = edges,
            spatialHash = spatialHash,
            system = system,
            lambda = 0.35
        )
    }

    return edges.toPointGraph(minWeight = 0.05)
}

fun exampleSystemSwitching

Example: switch systems over time while keeping the same dynamic edge store.

body — 65 lines, from line 68
fun exampleSystemSwitching(
    points: List<Vec3>,
    labels: List<Vec4>? = null
): PointGraph {
    val state = dynamicStateOf(points, labels)
    val edges = DynamicEdgeList(pointCount = state.pointCount, undirected = true)
    val spatialHash = Vec3SpatialHash(cellSize = 0.18)

    val systems = listOf<DynamicGraphSystem>(
        Vec3BreathingAnisotropicKnnSystem(
            k = 8,
            ttl = 2.5f,
            reinforce = 1.5,
            maxWeight = 8.0,
            mutualOnly = true,
            queryRadius = 0.45
        ),
        Vec3PersistentProximityHysteresisSystem(
            rEnter = 0.12,
            rExit = 0.18,
            ttl = 3.0f,
            reinforce = 2.0,
            maxWeight = 8.0,
            labelBias = 0.3
        ),
        Vec3SignalRoutingGraphSystem(
            neighborhoodK = 12,
            ttl = 2.5f,
            reinforce = 1.0,
            maxWeight = 8.0,
            routeCount = 2,
            maxNeighborRadius = 0.40
        ),
        Vec3LocalTangentTriangulationSystem(
            neighborhoodK = 10,
            ttl = 2.0f,
            reinforce = 0.8,
            maxWeight = 8.0,
            maxNeighborRadius = 0.35
        ),
        Vec3AlphaEventHypergraphCollapseSystem(
            neighborhoodK = 10,
            alphaRadius = 0.22,
            ttl = 2.3f,
            reinforcePerUnitArea = 1.1,
            maxWeight = 8.0,
            maxNeighborRadius = 0.30
        )
    )

    val dt = 1f / 60f
    repeat(150) { frame ->
        val system = systems[(frame / 30) % systems.size]
        stepDynamicGraphWithExponentialDecay(
            dt = dt,
            state = state,
            edges = edges,
            spatialHash = spatialHash,
            system = system,
            lambda = 0.35
        )
    }

    return edges.toPointGraph(minWeight = 0.05)
}

fun exampleDynamicGraphToPathCover

Example: snapshot into PointGraph, then reuse the existing path utilities.

fun exampleDynamicGraphToPathCover(
    points: List<Vec3>,
    labels: List<Vec4>? = null,
    anchor: Int = 0
): GraphPathSetResult {
    val graph = exampleDynamicGraphPipeline(points, labels)
    return graphAnchoredGreedyThenDiameterCover(graph, anchor)
}