All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.it.unibo.collektive.stdlib.Spreading.kt Maven / Gradle / Ivy

There is a newer version: 11.1.3
Show newest version
package it.unibo.collektive.stdlib

import it.unibo.collektive.aggregate.api.Aggregate
import it.unibo.collektive.aggregate.api.operators.share
import it.unibo.collektive.field.Field
import it.unibo.collektive.field.operations.minBy
import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads

/**
 * Compute the [Distance] from the closest [source], starting from [bottom] and up to [top].
 *
 * the [Distance] between neighboring devices is computed using the [metric] function,
 * the distance summation is governed by the [accumulateDistance] function.
 */
inline fun > Aggregate.distanceTo(
    source: Boolean,
    bottom: Distance,
    top: Distance,
    crossinline accumulateDistance: (Distance, Distance) -> Distance,
    crossinline metric: () -> Field,
): Distance = gradientCast(
    source = source,
    local = if (source) bottom else top,
    bottom = bottom,
    top = top,
    accumulateData = { neighborToSource, hereToNeighbor, _ -> accumulateDistance(neighborToSource, hereToNeighbor) },
    accumulateDistance,
    metric,
)

/**
 * Compute the distance from the closest [source], using [Int]egers.
 *
 * The distance between neighboring devices is computed using the [metric] function,
 * and defaults to the hop distance.
 */
@JvmOverloads
inline fun  Aggregate.intDistanceTo(
    source: Boolean,
    crossinline metric: () -> Field = { neighboring(1) },
): Int = distanceTo(source, 0, Int.MAX_VALUE, Int::plus, metric)

/**
 * Compute the distance from the closest [source], using [Double]s.
 *
 * The distance between neighboring devices is computed using the [metric] function,
 * and defaults to the hop distance.
 */
@JvmOverloads
inline fun  Aggregate.distanceTo(
    source: Boolean,
    crossinline metric: () -> Field = { neighboring(1.0) },
): Double = distanceTo(source, 0.0, Double.POSITIVE_INFINITY, Double::plus, metric)

/**
 * Propagate [local] values across a spanning tree starting from the closest [source].
 *
 * If there are no sources and no neighbors, default to [local] value.
 * The [metric] function is used to compute the distance between devices in form of a field of [Distance]s.
 * [Distance]s must be in the [[bottom], [top]] range, [accumulateDistance] is used to sum distances.
 * [accumulateData] is used to modify data from neighbors on the fly, and defaults to the identity function.
 */
@JvmOverloads
inline fun > Aggregate.gradientCast(
    source: Boolean,
    local: Value,
    bottom: Distance,
    top: Distance,
    crossinline accumulateData: (Distance, Distance, Value) -> Value = { _, _, data -> data },
    crossinline accumulateDistance: (Distance, Distance) -> Distance,
    crossinline metric: () -> Field,
): Value {
    val topValue = top to local
    return share(topValue) { neighborData ->
        val paths = neighborData.alignedMap(metric()) { (fromSource, data), toNeighbor ->
            val totalDistance = accumulateDistance(fromSource, toNeighbor)
            val newData = accumulateData(fromSource, toNeighbor, data)
            totalDistance to newData
        }
        when {
            source -> bottom to local
            else -> paths.minBy(base = topValue) { it.first } // sort by distance from the nearest source
        }
    }.second // return the data
}

/**
 * Propagate [local] values across a spanning tree starting from the closest [source].
 *
 * If there are no sources and no neighbors, default to [local] value.
 * The [metric] function is used to compute the distance between devices in form of a field of [Int]s.
 * [accumulateData] is used to modify data from neighbors on the fly, and defaults to the identity function.
 */
@JvmOverloads
@JvmName("gradientCastInt")
inline fun  Aggregate.gradientCast(
    source: Boolean,
    local: Type,
    crossinline accumulateData: (Int, Int, Type) -> Type = { _, _, data -> data },
    crossinline metric: () -> Field = { neighboring(1) },
): Type = gradientCast(source, local, Int.MIN_VALUE, Int.MAX_VALUE, accumulateData, Int::plus, metric)

/**
 * Propagate [local] values across a spanning tree starting from the closest [source].
 *
 * If there are no sources and no neighbors, default to [local] value.
 * The [metric] function is used to compute the distance between devices in form of a field of [Double]s.
 * [accumulateData] is used to modify data from neighbors on the fly, and defaults to the identity function.
 */
@JvmOverloads
@JvmName("gradientCastDouble")
inline fun  Aggregate.gradientCast(
    source: Boolean,
    local: Type,
    crossinline accumulateData: (Double, Double, Type) -> Type = { _, _, data -> data },
    crossinline metric: () -> Field = { neighboring(1.0) },
): Type = gradientCast(source, local, 0.0, Double.POSITIVE_INFINITY, accumulateData, Double::plus, metric)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy