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

protelis.coord.spreading.pt Maven / Gradle / Ivy

There is a newer version: 17.7.1
Show newest version
module protelis:coord:spreading
import org.apache.commons.math3.util.FastMath.floor
import protelis:lang:utils
import protelis:state:time

/*
 * Add v to the field of distances from the current device.
 *
 * @param v num, distance to add
 * @return  num, field of distances from the current device
 */
public def addRange(v) {
    addRangeWithMetric(v, nbrRange)
}

/*
 * Add of 1 the field of distances of the current device's neighbors.
 *
 * @return num, field of distances from the current device
 */
public def addRangeHop() {
    addRangeWithMetric(1, nbrRangeHop)
}

/*
 * Add v to the field of distances from the current device.
 *
 * @param v      num, distance to add
 * @param metric () -> num, estimate distance from other devices
 * @param speed  num, communication speed
 * @return       num, field of distances from the current device
 */
public def addRangeWithLag(v, metric, speed) {
    addRangeWithMetric(v, () -> { nbrRangeLag(metric, nbrLag, speed) })
}

/*
 * Add v to the field of distances from the current device.
 *
 * @param v      num, distance to add
 * @param metric () -> num, estimate distance from other devices
 * @return       num, field of distances from the current device
 */
public def addRangeWithMetric(v, metric) {
    v + metric.apply()
}

/**
 * Constrain the spreading of broadcast function only within a region.
 *
 * @param region bool, whether the function is spreaded or not
 * @param null   T, default value where f is not spreaded
 * @param source bool, whether the current device is a source
 * @param        T, value what to broadcast
 * @return       T, broadcast inside the region, return null otherwise
 */
public def boundBroadcast(region, null, source, value) {
    boundSpreading(region, () -> { broadcast(source, value) }, null)
}

/**
 * Constrain the spreading of G function only within a region.

 * @param region     bool, whether the function is spreaded or not
 * @param null       T, default value where f is not spreaded
 * @param source     bool, whether the current device is a source
 * @param initial    T, initial value of the computation
 * @param metric     () -> num, estimate distance from other devices
 * @param accumulate (T) -> T, how to manage the value
 * @return           T, accumulated value
 */
public def boundG(region, null, source, initial, metric, accumulate) {
    boundSpreading(region, () -> {
        G(source, initial, metric, accumulate)
    }, null)
}

/*
 * Distance from the current to the closest source.
 *
 * @param region bool, where to compute distanceTo
 * @param source bool, whether the device is a source
 * @return       num, field of minimum distances to the closest source
 */
public def boundDistanceTo(region, source) {
    boundSpreading(region, () -> { distanceTo(source) }, Infinity)
}

/**
 * Constrain the spreading of f only across a region.
 *
 * @param region bool, whether the function is spreaded or not
 * @param f      () -> T,  function to be spreaded
 * @param null   T, default value where f is not spreaded
 * @return       T, apply f inside the region, null outside
 */
public def boundSpreading(region, f, null) {
    if (region) {
        f.apply()
    } else {
        null
    }
}

/**
 * Constrain the spreading of f only within devices close to the source.
 *
 * @param range () -> bool, how to determine the range
 * @param f     () -> T, function to be spreaded
 * @param null  T, default value where f is not spreaded
 * @return      T, apply f inside the region, null outside
 */
public def boundSpreadingWithRange(range, f, null) {
    boundSpreading(range.apply(), f, null);
}

/*
 * Broadcast value across a spanning tree starting from the source.
 *
 * @param source bool, whether the current device is a source
 * @param value  T, what to broadcast
 * @return       T, broadcasted value
 */
public def broadcast(source, value) {
    broadcastWithMetric(source, value, nbrRange)
}

/*
 * Broadcast value across a spanning tree starting from the source.
 *
 * @param source bool, whether the current device is a source
 * @param value  T, what to broadcast
 * @param metric () -> num, estimate distance from other devices
 * @return       T, broadcasted value
 */
public def broadcastWithMetric(source, value, metric) {
    G(source, value, metric, identity)
}

/**
 * Dynamically computes distributed routes between regions of a network, and
 * dynamically adapts to shape and changes of the network topology. Examples
 * of its use include long-range reliable communications, or advanced crowd
 * steering applications in pervasive computing. The �channel� is a Boolean
 * field that is true for devices near the shortest route from a given
 * (distributed) source to a (distributed) destination.
 *
 * @param source   bool, whether the device is a source
 * @param dest     bool, whether the device is a destination
 * @param obstacle bool, whether the device is an obstacle
 * @param thr      num, threshold for Double comparison (e.g. 0.01)
 * @param width    num, how much to dilate the channel
 * @return         bool, true if the device is on the shortest path, false otherwise
 */
public def channel(source, dest, obstacle, thr, width) {
      boundSpreading(!obstacle, () -> {
          let d = distanceBetween(source, dest);
          if (d == Infinity) { false }
          else {
              distanceTo(distanceTo(source) + distanceTo(dest) <=  d + thr) <= width
          }
      }, false)
}

/**
 * Channel pattern.
 *
 * @param source   bool, whether the device is a source
 * @param dest     bool, whether the device is a destination
 * @param obstacle bool, whether the device is an obstacle
 * @param width    num, how much to dilate the channel
 * @return         bool, true if the device is on the shortest path, false otherwise
 */
public def channel2(source, destination, obstacle, width) {
      boundSpreading(!obstacle, () -> {
          distanceTo(shortestPath(source, destination)) <= width
      }, false)
}

/**
 * @param source bool, whether the device is a source
 * @param range  num, range
 * @return       bool, true if the device is closer than range to the source
 */
public def closerThan(source, range) {
    distanceToWithMetric(source, nbrRange) < range
}

/**
 * @param source bool, whether the device is a source
 * @param metric () -> num, how to estimate the distance
 * @param range  num,  range
 * @return       bool, true if the device is closer than range to the source
 */
public def closerThanWithMetric(source, metric, range) {
    distanceToWithMetric(source, metric) < range
}

/**
 * Self-healing gradcast algorithm that reconfigures in O(diameter) time.
 * Requires euclidean metric. The CRF-Gradient algorithm handles this problem
 * by splitting the calculation into constraint and restoring force behaviors.
 * When constraint is dominant, the value of a device gx(t) stays fixed or
 * decreases, set by the triangle inequality from its neighbors� values.  When
 * restoring force is dominant, gx(t) rises at a fixed velocity v0.
 *
 * @param source bool,  whether the device is a source
 * @param metric () -> num, how to estimate distances without lag
 * @param maxHop num, communication max range
 * @return       num, minimum distance from the source
 */
public def crfGradient(source, metric, maxHop) {
    rep (potential <- [Infinity, 0]) {
        mux (source) {
            [0, 0]
        } else {
            let d = nbr(potential).get(0);
            let dt = self.getDeltaTime();
            mux (anyHood(addRangeWithLag(d, metric, potential.get(1)) < potential.get(0))) {
                minHood([d + metric.apply(), 0])
            } else {
                let v0 = if (dt == 0) { maxHop } else { maxHop / (dt * 12) };
                [potential.get(0) + v0 * dt, v0]
            }
        }
    }.get(0)
}

/**
 * Dilate a spatial region.
 *
 * @param region bool, whether the device is inside the region
 * @param width  num, how much to dilate
 * @return       bool, dilated region
 */
 public def dilate(region, width) {
     dilateWithMetric(region, nbrRange, width)
 }

/**
 * Dilate a spatial region.
 *
 * @param region bool, whether the device is inside the region
 * @param metric () -> num, how to estimate the distance between devices
 * @param width  num, how much to dilate
 * @return       bool, dilated region
 */
public def dilateWithMetric(region, metric, width) {
     distanceToWithMetric(region, metric) < width
}

/**
 * Forecast obstacles along a path to the source.
 *
 * @param source   bool, whether the device is a source
 * @param obstacle bool, whether the device is an obstacle
 * @return         bool, true if the device encounter an obstacle within the shortest
 * path towards the closest source, false otherwise
 */
public def directProjection(source, obstacle) {
    directProjectionWithMetric(source, obstacle, nbrRange)
}

/**
 * Forecast obstacles along a path to the source.
 *
 * @param source   bool, whether the device is a source
 * @param obstacle bool, whether the device is an obstacle
 * @param metric   () -> num, how to estimate neighbors distances
 * @return         bool, true if the device encounter an obstacle within the shortest
 * path towards the closest source, false otherwise
 */
public def directProjectionWithMetric(source, obstacle, metric) {
    G(source, obstacle, metric, (v) -> { obstacle || Gnull(v, false) })
}

/**
 * Smallest distance between source and destination devices.
 *
 * @param source bool, whether the current device is a source
 * @param dest   bool, whether the current device is a destination
 * @return       num, smallest distance between source and destination devices
 */
public def distanceBetween(source, dest) {
    distanceBetweenWithMetric(source, dest, nbrRange)
}

/**
 * Smallest distance between source and destination devices.
 *
 * @param source bool, whether the current device is a source
 * @param dest   bool, whether the current device is a destination
 * @param metric () -> num, estimate distance from other devices
 * @return       num, smallest distance between source and destination devices
 */
public def distanceBetweenWithMetric(source, dest, metric) {
    G(source, distanceToWithMetric(dest, metric), metric, identity)
}

/*
 * Distance from the current to the closest source.
 *
 * @param source bool, whether the current device is a source
 * @return       num, distance to the closest source
 */
public def distanceTo(source) {
    distanceToWithMetric(source, nbrRange)
}

/*
 * Distance from the current to the closest source.
 *
 * @param source bool, whether the device is a source
 * @param metric () -> num, estimate distance from other devices
 * @return       num, field of minimum distances to the closest source
 */
public def distanceToWithMetric(source, metric) {
    G(source, 0, metric, (v) -> { v + metric.apply() })
}

/**
 * Used by flexGradient
 */
def slope(d, minD, metric) {
    let nrange = metric.apply();
    if (nrange > 0) {
        let ndv = nbr(d);
        let m = max(minD, maxHood(nrange));
        maxHood([(d - ndv)/m, ndv, m])
    } else { [0, d, 0] }
}

/**
 * Flex-Gradient.
 *
 * @param source     bool, whether the device is a source
 * @param epsilon    num, tolerance
 * @param rate       num, communication rate
 * @param range      num, communication range
 * @param distortion num, distortion
 * @param metric     () -> num, estimate distance from other devices
 */
public def flexGradient(source, epsilon, rate, range, distortion, metric) {
    rep (d <- Infinity) {
        mux (source) {
            0
        } else {
            let minD = range * distortion;
            let slopeInfo = slope(d, minD, metric);
            let maxSlope = slopeInfo.get(0);
            let msd = slopeInfo.get(1);
            let msr = slopeInfo.get(2);
            let ct = minHood(nbr(d) + max(minD, maxHood(metric.apply())));
            mux ((d > range && d > ct * 2) || cyclicTimer((d + self.getDeltaTime()) * rate)) {
                ct
            } else {
                mux (maxSlope > (1 + epsilon)) {
                    msd + msr * (1 + epsilon)
                } else {
                    mux (maxSlope < (1 - epsilon)) {
                        msd + msr * (1 - epsilon)
                    } else {
                        d
                    }
                }
            }
        }
    }
}

/*
 * Propagate values across a spanning tree starting from the closest source.
 *
 * @param source     bool, whether the current device is a source
 * @param initial    T, initial value of the computation
 * @param metric     () -> num, estimate distance from other devices
 * @param accumulate (T) -> T, how to accumulate the value
 * @return           T, accumulated value
 */
public def G(source, initial, metric, accumulate) {
    rep (distanceValue <- [Infinity, initial]) {
        mux (source) {
            // If the device is a source then G return a 0 potential
            // and the initial value
            [0, initial]
        } else {
            // The other device potentials are requested
            let ndv = nbr(distanceValue);
            // G returns the value related to the minimum potential
            // TODO do we need a default?
            minHood([
                // potential estimation
                ndv.get(0) + metric.apply(),
                // values estimation
                accumulate.apply(ndv.get(1))
            ])
        }
    }.get(1) // return the accumulated value
}

/**
 * Wrapper for G error.
 * For example: G(aBool, aBool, aMetric, (v) -> { Gnull(v, false) ... }
 * assure that G is not broken in case minHood([..., ...]) returns Infinity.
 *
 * @param v       T, value to be checked
 * @param default T, default value to avoid to broke G
 * @return        T, v or default
 */
public def Gnull(v, default) {
    mux (v == Infinity) {
        default
    } else {
        v
    }
}

/**
 * Gradcast.
 *
 * @param source     bool, whether the device is a source
 * @param gradient   num, gradient to follow
 * @param local      T, local value
 * @param accumulate (T) -> T, how to accumulate local values
 * @return           T, accumulated value
 */
public def gradcast(source, gradient, local, accumulate) {
    rep (value <- local) {
        mux (source) {
            local
        } else {
            minHood([nbr(gradient.apply()), accumulate.apply(nbr(value))]).get(1)
        }
    }
}

/**
 * Determine the smallest distance from the current device to the source.
 *
 * @param source bool, whether the device is a source
 * @param init   num, distance initial value
 * @param metric () -> num, estimate distance from other devices
 * @param range  num, communication range
 * @return       num, minimum distance from the closest source
 */
public def gradient(source, init, metric, range) {
    rep (distance <- [Infinity, 0]) {
        mux (source) {
            [init, 0]
        } else {
            let d = distance.get(0);
            let v = distance.get(1);
            mux (anyHood(addRangeWithLag(nbr(distance).get(0), metric, v) <= d)) {
                let ndv = nbr(distance);
                minHood([ndv.get(0) + metric.apply(), 0])
            } else {
                let v0 = range / 2;
                [d + v0 * self.getDeltaTime(), v0]
            }
        }
    }.get(0)
}

/**
 * Count the number of neighbors.
 *
 * @return num, number of neighbors
 */
public def neighborhood() {
     sumHood(nbr(1))
}

/**
 * Communication latency.
 *
 * @return num, communication latencies between this device and its
 * neighbors
 */
public def nbrLag() {
    self.nbrLag()
}

/*
 * Estimate the distance of the current device.
 *
 * @return num, field of distances from the current device
 */
public def nbrRange() {
    self.nbrRange()
}

/*
 * Estimate the distance from the current device.
 *
 * @return num, field of 1s for each neighbor
 */
public def nbrRangeHop() {
    1
}

/*
 * Estimate the distance of the current device.
 *
 * @param metric    () -> num, how to estimate distances
 * @param lagmetric () -> num, how to estimate latencies
 * @param speed     num, communication speed
 * @return          num, field of distances from the current device
 */
public def nbrRangeLag(metric, lagMetric, speed) {
    metric.apply() + (lagMetric.apply() + self.getDeltaTime()) * speed
}

/**
 * Shortest path according to a potential.
 *
 * @param source    bool, whether the device is a source
 * @param potential num, potential
 * @return          bool, true if the device is in the shortest path
 * @see rendezvous
 */
public def descend(source, potential) {
    rep (path <- source) {
        let nextStep = minHood(nbr([potential, self.getDeviceUID()]));
        if (nextStep.size() > 1) {
            let candidates = nbr([nextStep.get(1), path]);
            source || anyHood([self.getDeviceUID(), true] == candidates)
        } else { source }
    }
}

/**
 * Shortest path.
 *
 * @param source bool, whether the device is the source
 * @param dest   bool, whether the device is the destination
 * @return       bool, true if the device is in the shortest path
 * @see descend, shortestPath
 */
public def rendezvous(source, dest) {
    descend(source, distanceTo(dest))
}

/**
 * Dynamically computes the shortest route between regions of a network, and
 * dynamically adapts to shape and changes of the network topology. The �shortest path�
 * is a Boolean field that is true for devices near the shortest route from a given
 * (distributed) source to a (distributed) destination.
 *
 * @param source bool, whether the device is the source
 * @param dest   bool, whether the device is the destination
 * @return       bool, true if the device is in the shortest path
 * @see rendezvous
 */
public def shortestPath(source, destination) {
    rep (path <- false) {
        mux (source) {
            true
        } else {
            // any device on the shortest path
            anyHood(
                // check whether a neigh is on the shortest path AND the current device is in the shortest path
                nbr (path) &&
                    (distanceTo(destination) == nbr( // if my distance is the same as the collected one
                        minHood( // get the closest distance
                            nbr(distanceTo(destination)) // get the neighbors distances from the destination
                        )
                    )
                )
            )
        }
    }
}

/**
 * Entry point for a computation.
 *
 * @param source bool, whether the device is a source
 * @param range  num, spreading constraint
 * @param f      () -> T, entry point
 * @param null   T, default value
 * @return       T, apply f if device is inside the spreading region, null outside
 */
public def vm(source, range, f, null) {
    vmWithMetric(source, nbrRange, range, f, null)
}

/**
 * Entry point for a computation.
 *
 * @param source bool, whether the device is a source
 * @param metric () -> num, how to estimate neighbors distances
 * @param range  num, spreading constraint
 * @param f      () -> T, entry point
 * @param null   T, default value
 * @return       T, apply f if device is inside the spreading region, null outside
 */
public def vmWithMetric(source, metric, range, f, null) {
    boundSpreadingWithRange(() -> {
        closerThanWithMetric(source, metric, range)
    }, f, null)
}

/**
 * Computing a Voronoi partition is an operation that is frequently useful in
 * distributed systems. Given an initial set of seed devices, a Voronoi
 * partition assigns each device to the partition of the nearest seed,
 * effectively breaking the network up into zones of influence around key
 * elements.
 *
 * @param source bool, whether the device is a seed
 * @param id     T, partition id
 * @return       T, partition of the nearest seed
 */
public def voronoiPatitioning(source, id) {
    voronoiPatitioningWithMetric(source, id, nbrRange)
}

/**
 * Computing a Voronoi partition is an operation that is frequently useful in
 * distributed systems. Given an initial set of seed devices, a Voronoi
 * partition assigns each device to the partition of the nearest seed,
 * effectively breaking the network up into zones of influence around key
 * elements.
 *
 * @param source bool, whether the device is a seed
 * @param id     T, partition id
 * @param metric () -> num, how to estimate the distances of the neighbors
 * @return       T, partition of the nearest seed
 */
public def voronoiPatitioningWithMetric(seed, id, metric) {
    G(seed, id, metric, identity)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy