protelis.coord.graph.pt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of protelis-lang Show documentation
Show all versions of protelis-lang Show documentation
Essential libraries for the Protelis language
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)
}