Libraries
phyelds.libraries collects reusable aggregate functions, all written with the
same primitives you use. Reading their source is a good way to learn idiomatic
phyelds. All of them must be called from inside an aggregate program.
Device: phyelds.libraries.device
| Function |
Returns |
local_id() |
the id of the device |
local_position() |
its position |
sense(name) |
the value of sensor name (None if missing) |
store(name, value) |
writes an output, for the platform to read (actuation, metrics) |
Distances: phyelds.libraries.distances
| Function |
Returns |
neighbors_distances() |
a field with the Euclidean distance to each neighbor (0 for the device itself) |
hops_distance() |
a field with 1 for each neighbor and 0 for the device itself |
Spreading: phyelds.libraries.spreading
| Function |
Returns |
distance_to(source, distances) |
the gradient: distance from the nearest device where source is true |
broadcast(source, data, distances) |
the data of the nearest source, spread along the gradient |
cast_from(source, data, accumulation, distances) |
like broadcast, applying accumulation at each hop |
from phyelds.calculus import aggregate
from phyelds.libraries.device import local_id, sense
from phyelds.libraries.distances import hops_distance
from phyelds.libraries.spreading import broadcast
@aggregate
def leader_id():
# every device learns the id of the nearest source
return broadcast(sense("source"), local_id(), hops_distance())
Collection: phyelds.libraries.collect
Collection is the dual of spreading: values flow towards the source along the
gradient (the potential), and are accumulated on the way.
| Function |
Returns (at the source: over the whole network) |
collect_with(potential, local, accumulation) |
local values accumulated with accumulation |
count_nodes(potential) |
the number of devices |
sum_values(potential, local) |
the sum of local |
collect_or(potential, local) |
whether any device has local true |
from phyelds.libraries.collect import count_nodes
from phyelds.libraries.spreading import distance_to
@aggregate
def network_size():
potential = distance_to(sense("source"), hops_distance())
return count_nodes(potential)
The channel of the playground combines
both: a collection of collect_or along one gradient, spread again by another.
Gossip: phyelds.libraries.gossip
| Function |
Returns |
gossip_min(value), gossip_max(value) |
the minimum / maximum of value over the network |
gossip(value, callback) |
value combined over the network with callback (e.g. set.union) |
stabilizing_gossip(value, max_diameter, callback) |
a gossip that forgets devices farther than max_diameter hops, so it can adapt when values change |
Plain gossip only moves in one direction: gossip_min never forgets a minimum, even
if the device that had it leaves.
Leader election: phyelds.libraries.leader_election
elect_leaders(area, distances) is true on the devices elected as leaders, with
roughly one leader every area of distance (a self-stabilising, UUID-based
symmetry breaking).
Time: phyelds.libraries.time
| Function |
Returns |
local_time() |
the time of the device |
counter() |
how many rounds this call has run |
decay(value, rate) |
a value that starts at value and decreases by rate each round, down to 0 |