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

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

There is a newer version: 17.6.0
Show newest version
module protelis:coord:graph
import protelis:lang:utils
import protelis:coord:tree
import protelis:coord:nonselfstabilizing:accumulation
import java.lang.Double.POSITIVE_INFINITY
import java.lang.Double.NEGATIVE_INFINITY

/**
 * Check if circular dependencies exist.
 *
 * A circular dependency exists if a device is self-referencing itself or a
 * transitive dependency exists.
 *
 * @param myId    T, device id
 * @param inbound [T], inbound connections
 * @return        bool, true if the device is part of a circular dependency,
 *                false otherwise
 */
public def circularDependency(myId, inbound) {
    hasTransitiveDependency(myId, inbound) || hasSelfDependency(myId, inbound)
}

/**
 * Check if a device is self-referencing itself.
 *
 * @param myId    T, device id
 * @param inbound [T], inbound connections
 * @return        bool, true if the device is self-referencing itself
 */
public def hasSelfDependency(myId, inbound) {
    inbound.contains(myId)
}

/**
 * Check if a device is part of a transitive circular dependency.
 *
 * @param myId    T, device id
 * @param inbound [T], inbound connections
 * @return        bool, true if the device is part of a transitive circular
 *                dependency
 */
public def hasTransitiveDependency(myId, inbound) {
    isNotEmpty(mux (inbound != []) {
        share (v, nbrV <- inbound) {
            v.union(
                hood(
                    (a, b) -> { a.union(b) }, [], nbrWrapper(myId, inbound, nbrV, [])
                )
            )
        }
    } else {
        []
    }.intersection([myId]))
}

/**
 * Get the greatest lower bound for a set of devices.
 *
 * @param myId    T, device id
 * @param inbound [T], inbound connections
 * @param nodes   T, node on which estimate the greatest lower bound
 * @return        bool, true if the device is part of greatest lower bound
 *                set of devices, false otherwise
 */
public def greatestLowerBound(myId, inbound, nodes) {
    let spread = spreadBoundValue(myId, inbound, nodes);
    let v =
        if (spread.get(0).size() == nodes.size()) { spread.get(1) }
        else { POSITIVE_INFINITY };
    gossip(v, min) == v
}

/**
 * Check if a device is a leaf of the graph.
 *
 * A device is a leaf when none of the other devices refers to it as an
 * inbound connection, and the device has no outbound connections.
 *
 * @param myId    T, device id
 * @param inbound [T], inbound connections
 * @return        bool, true if the device is a leaf, false otherwise
 */
public def isLeaf(myId, inbound) {
    !unionHood(nbr(inbound)).contains(myId)
}

/**
 * Check if a device is a root of the graph.
 *
 * A device is a root when it has no inbound connections.
 *
 * @param inbound [T], inbound connections
 * @return        bool, true if the device is a root, false otherwise
 */
public def isRoot(inbound) {
    isEmpty(inbound)
}

/**
 * @param myId    T, device id
 * @param inbound [T], inbound connections
 * @return        bool, true if the device is parrent of the current device
 */
public def isParent(myId, inbound) {
    inbound.intersection(nbr([myId])).size() > 0
}

/**
 * Get the least upper bound for a set of devices.
 *
 * @param myId    T, device id
 * @param outbound [T], outbound connections
 * @param nodes   T, node on which estimate the least upper bound
 * @return        bool, true if the device is part of least upper bound
 *                set of devices, false otherwise
 */
public def leastUpperBound(myId, outbound, nodes) {
    greatestLowerBound(myId, outbound, nodes)
}

/**
 * This nbrWrapper get the messages coming only from a subset of neighbors.
 * When working with graph, nbrWrabber must be used instead of nbr. Otherwise the
 * graph logical structure is broken.
 *
 * If connections is the set of inbound connections, then nbrWrapper returns
 * only the messages coming from the parents of the current device, replacing
 * messages from the children with null. Using outbound connections does the
 * opposite.
 *
 * @param myId        T, device id
 * @param connections [T], inbound connections
 * @param message     T', field on which nbr is applied
 * @param null        T', placeholder for devices which not fulfill the
 *                    filtering criteria
 * @return            T', filtered set of messages
 */
public def nbrWrapper(myId, connections, nbrMessage, null) {
    let res = mux (isParent(myId, connections)) { nbrMessage } else { null };
    mux (res == []) { null } else { res }
}

def spreadBoundValue(myId, connections, nodes) {
    share (nbrV <- [[NEGATIVE_INFINITY], NEGATIVE_INFINITY]) {
        mux (nodes.contains(myId)) {
            [intersection(nodes, connections).union([myId]), 0]
        } else {
            let aggr = hood(
                (a, b) -> {
                    let c = intersection(nodes, a.get(0));
                    if (isEmpty(c)) {
                        [intersection(nodes, b.get(0)), b.get(1)]
                    } else {
                        if (c.size() == nodes.size()) { a }
                            else {
                            if (isNotEmpty(intersection(nodes, b.get(0)))) {
                                [c.union(b.get(0)), max(a.get(1), b.get(1))]
                            } else { [c, a.get(1)] }
                        }
                    }
                }, [], nbrWrapper(myId, connections, nbrV, [[NEGATIVE_INFINITY], NEGATIVE_INFINITY])
            );
            if (isEmpty(aggr)) { [[NEGATIVE_INFINITY], NEGATIVE_INFINITY] }
            else { [aggr.get(0), aggr.get(1) + 1] }
        }
    }
}

def intersection(list1, list2) {
    list1.intersection(list2)
}

def isEmpty(list) {
    list.size() == 0
}

def isNotEmpty(list) {
    !isEmpty(list)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy