def add_node(self, node=None, pos=None, ori=None, commRange=None): """ Add node to network. Attributes: `node` -- node to add, default: new node is created `pos` -- position (x,y), default: random free position in environment `ori` -- orientation from 0 to 2*pi, default: random orientation """ if (not node): node = Node(commRange=commRange) assert(isinstance(node, Node)) if not node.network: node.network = self else: logger.warning('Node is already in another network, can\'t add.') return None pos = pos if pos is not None else self.find_random_pos(n=100) ori = ori if ori is not None else rand() * 2 * pi ori = ori % (2 * pi) if (self._environment.is_space(pos)): Graph.add_node(self, node) self.pos[node] = array(pos) self.ori[node] = ori self.labels[node] = str(node.id) logger.debug('Node %d is placed on position %s.' % (node.id, pos)) self.recalculate_edges([node]) else: logger.error('Given position is not free space.') return node
def send(self, message): """ Send a message to nodes listed in message's destination field. Note: Destination should be a list of nodes or one node. Update message's source field and inserts in node's outbox one copy of it for each destination. """ if not self.power.have_energy(): self.n_transmitted_failed_power += 1 self.energy.append(self.power.energy) logger.debug("Node %d doesn't have enough energy to send message [energy=%5.3f]" % (self.id, self.power.energy)) return message.source = self message.destination = isinstance(message.destination, list) and\ message.destination or [message.destination] msg_len = message.message_length() for destination in message.destination: self.power.decrease_tx_energy(msg_len) self.energy.append(self.power.energy) self.n_transmitted += 1 logger.debug('Node %d sent message %s [%d].' % (self.id, message.data, msg_len)) m = message.copy() m.destination = destination self.outbox.insert(0, m)
def send(self, message): """ Send a message to nodes listed in message's destination field. Note: Destination should be a list of nodes or one node. Update message's source field and inserts in node's outbox one copy of it for each destination. """ if not self.power.have_energy(): self.n_transmitted_failed_power += 1 self.energy.append(self.power.energy) logger.debug( "Node %d doesn't have enough energy to send message [energy=%5.3f]" % (self.id, self.power.energy)) return message.source = self message.destination = isinstance(message.destination, list) and\ message.destination or [message.destination] msg_len = message.message_length() for destination in message.destination: self.power.decrease_tx_energy(msg_len) self.energy.append(self.power.energy) self.n_transmitted += 1 logger.debug('Node %d sent message %s [%d].' % (self.id, message.data, msg_len)) m = message.copy() m.destination = destination self.outbox.insert(0, m)
def send(self, destination, message): logger.debug('Sending message from %s to %s.' % (repr(message.source), destination)) if destination in self.nodes(): destination.push_to_inbox(message) else: raise PymoteMessageUndeliverable('Destination not in network.', message)
def remove_node(self, node): """ Remove node from network. """ if node not in self.nodes(): logger.error("Node not in network") return Graph.remove_node(self, node) del self.pos[node] del self.labels[node] node.network = None logger.debug('Node with id %d is removed.' % node.id)
def add_node(self, node=None, pos=None, ori=None, commRange=None, find_random=False): """ Add node to network. Attributes: `node` -- node to add, default: new node is created `pos` -- position (x,y), default: random free position in environment `ori` -- orientation from 0 to 2*pi, default: random orientation """ if (not node): node = Node(commRange=commRange or self.comm_range) if not node.commRange: node.commRange = commRange or self.comm_range assert (isinstance(node, Node)) if not node.network: node.network = self else: logger.warning('Node is already in another network, can\'t add.') return None pos = pos if (pos is not None and not isnan(pos[0])) else self.find_random_pos(n=100) ori = ori if ori is not None else rand() * 2 * pi ori = ori % (2 * pi) got_random = False if find_random and not self._environment.is_space(pos): pos = self.find_random_pos(n=100) got_random = True if (self._environment.is_space(pos)): Graph.add_node(self, node) self.pos[node] = array(pos) self.ori[node] = ori self.labels[node] = ('C' if node.type == 'C' else "") + str( node.id) logger.debug('Node %d is placed on position %s %s %s' % (node.id, pos, '[energy=%5.3f]' % node.power.energy if node.power.energy != EnergyModel.E_INIT else '', 'Random' if got_random else '')) self.recalculate_edges([node]) else: Node.cid -= 1 logger.error('Given position is not free space. [%s] %s' % (Node.cid, pos)) node = None return node
def _are_conditions_satisfied(self, net): cr = net.nodes()[0].commRange if self.connected and not is_connected(net): logger.debug("Not connected") return round(0.2 * cr) elif self.degree: logger.debug("Degree not satisfied %f" % net.avg_degree()) diff = self.degree - net.avg_degree() diff = sign(diff) * min(abs(diff), 7) return round((sign(diff) * (round(diff))**2) * cr / 100) return 0
def _are_conditions_satisfied(self, net): cr = net.nodes()[0].commRange if self.connected and not is_connected(net): logger.debug("Not connected") return round(0.2*cr) elif self.degree: logger.debug("Degree not satisfied %f" % net.avg_degree()) diff = self.degree-net.avg_degree() diff = sign(diff)*min(abs(diff), 7) return round((sign(diff)*(round(diff))**2)*cr/100) return 0
def send(self, destination, message): logger.debug('Sending message from %s to %s (%s).' % (repr(message.source), destination, message.data)) if destination in self.nodes(): destination.push_to_inbox(message) #if message.source: #message.source.power.decrease_tx_energy(message.message_length()) # TODO else: raise PymoteMessageUndeliverable('Destination not in network.', message)
def estimate_position(self, node): TRESHOLD = .1 MAX_ITER = 10 landmarks = [] # get landmarks with hopsize data if self.dataKey in node.memory: landmarks = node.memory[self.dataKey].keys() # calculate estimated distances if len(landmarks) >= 3: dist = lambda x, y: sqrt(dot(x - y, x - y)) landmark_max_positions = [ array(node.memory[self.dataKey][lm][:2]) for lm in landmarks ] # take centroid as initial estimation pos = average(landmark_max_positions, axis=0) landmark_distances = [] landmark_positions = [] # only reliable anchors for lp in node.memory[self.dataKey].values(): threshold = FloodingUpdate.lookup.get(lp[2], 0.75) * node.commRange hl = dist(lp[:2], pos) / lp[2] logger.debug("Node=%s, Hop=%s, threshold=%s, hoplen=%s" % (node.id, lp[2], threshold, hl)) if hl > threshold and self.hopsizeKey in node.memory: # reliable landmark_distances.append( lp[2] * (node.memory[self.hopsizeKey] or 1)) landmark_positions.append(array(lp[:2])) # take centroid as initial estimation W = diag(ones(len(landmark_positions))) counter = 0 while True: J = array([(lp - pos) / dist(lp, pos) for lp in landmark_positions]) range_correction = array([ dist(landmark_positions[li], pos) - landmark_distances[li] for li, lm in enumerate(landmark_positions) ]) pos_correction = dot(linalg.inv(dot(dot(J.T, W), J)), dot(dot(J.T, W), range_correction)) logger.debug("Est. %s, %s, %s" % (node.id, pos, pos_correction)) pos = pos + pos_correction counter += 1 if sqrt(sum(pos_correction ** 2)) < \ TRESHOLD or counter >= MAX_ITER: logger.info("Trilaterate break %s" % counter) break if counter <= MAX_ITER: node.memory[self.positionKey] = pos node.memory['reliable'] = landmark_positions
def estimate_position(self, node): TRESHOLD = .1 MAX_ITER = 10 landmarks = [] # get landmarks with hopsize data if self.dataKey in node.memory: landmarks = node.memory[self.dataKey].keys() # calculate estimated distances if len(landmarks) >= 3: landmark_distances = [] landmark_positions = [] try: landmark_distances = [ node.memory[self.dataKey][lm][2] * node.memory[self.hopsizeKey] for lm in landmarks ] landmark_positions = [ array(node.memory[self.dataKey][lm][:2]) for lm in landmarks ] except: pass # take centroid as initial estimation pos = average(landmark_positions, axis=0) W = diag(ones(len(landmarks))) counter = 0 dist = lambda x, y: sqrt(dot(x - y, x - y)) while pos.any() != nan: J = array([(lp - pos) / dist(lp, pos) for lp in landmark_positions]) range_correction = array([ dist(landmark_positions[li], pos) - landmark_distances[li] for li, lm in enumerate(landmarks) ]) pos_correction = dot(linalg.inv(dot(dot(J.T, W), J)), dot(dot(J.T, W), range_correction)) pos = pos + pos_correction logger.debug("Est. %s, %s, %s" % (node.id, pos, pos_correction)) counter += 1 if sqrt(sum(pos_correction ** 2)) < \ TRESHOLD or counter >= MAX_ITER: logger.info("Trilaterate break %s" % counter) break if counter <= MAX_ITER: node.memory[self.positionKey] = pos node.memory['reliable'] = landmark_positions
def _are_conditions_satisfied(self, net): cr = net.nodes()[0].commRange if self.connected and not is_connected(net): logger.debug("Not connected") return round(0.2*cr) elif self.degree: diff = (self.degree-net.avg_degree())/self.degree if (abs(diff)<0.1): return 0 #diff = sign(diff)*min(abs(diff), 7) #adj = round((sign(diff)*(round(diff))**2)*cr/35) adj = sign(diff)/5.0 logger.debug("Degree not satisfied %f, %s, %s" % (net.avg_degree(), diff, adj)) return adj return 0
def __init__(self, network, **kwargs): self.network = network self.name = self.__class__.__name__ logger.debug('Instance of %s class has been initialized.' % self.name) for required_param in self.required_params: if required_param not in kwargs.keys(): raise PymoteAlgorithmException('Missing required param.') # set default params for dp, val in self.default_params.items(): self.__setattr__(dp, val) # override default params for kw, arg in kwargs.items(): self.__setattr__(kw, arg)
def estimate_position(self, node): TRESHOLD = .1 MAX_ITER = 10 landmarks = [] # get landmarks with hopsize data if self.dataKey in node.memory: landmarks = node.memory[self.dataKey].keys() # calculate estimated distances if len(landmarks) >= 3: dist = lambda x, y: sqrt(dot(x - y, x - y)) landmark_max_positions = [array(node.memory[self.dataKey][lm][:2]) for lm in landmarks] # take centroid as initial estimation pos = average(landmark_max_positions, axis=0) landmark_distances = [] landmark_positions = [] # only reliable anchors for lp in node.memory[self.dataKey].values(): threshold = FloodingUpdate.lookup.get(lp[2], 0.75) * node.commRange hl = dist(lp[:2], pos)/lp[2] logger.debug("Node=%s, Hop=%s, threshold=%s, hoplen=%s" %(node.id, lp[2], threshold, hl)) if hl > threshold and self.hopsizeKey in node.memory: # reliable landmark_distances.append(lp[2] * (node.memory[self.hopsizeKey] or 1)) landmark_positions.append(array(lp[:2])) # take centroid as initial estimation W = diag(ones(len(landmark_positions))) counter = 0 while True: J = array([(lp - pos) / dist(lp, pos) for lp in landmark_positions]) range_correction = array([dist(landmark_positions[li], pos) - landmark_distances[li] for li, lm in enumerate(landmark_positions)]) pos_correction = dot(linalg.inv(dot(dot(J.T, W), J)), dot(dot(J.T, W), range_correction)) logger.debug("Est. %s, %s, %s" %(node.id, pos, pos_correction)) pos = pos + pos_correction counter += 1 if sqrt(sum(pos_correction ** 2)) < \ TRESHOLD or counter >= MAX_ITER: logger.info("Trilaterate break %s" % counter) break if counter <= MAX_ITER: node.memory[self.positionKey] = pos node.memory['reliable'] = landmark_positions
def add_node(self, node=None, pos=None, ori=None, commRange=None, find_random=False): """ Add node to network. Attributes: `node` -- node to add, default: new node is created `pos` -- position (x,y), default: random free position in environment `ori` -- orientation from 0 to 2*pi, default: random orientation """ if (not node): node = Node(commRange=commRange or self.comm_range) if not node.commRange: node.commRange = commRange or self.comm_range assert(isinstance(node, Node)) if not node.network: node.network = self else: logger.warning('Node is already in another network, can\'t add.') return None pos = pos if (pos is not None and not isnan(pos[0])) else self.find_random_pos(n=100) ori = ori if ori is not None else rand() * 2 * pi ori = ori % (2 * pi) got_random = False if find_random and not self._environment.is_space(pos): pos = self.find_random_pos(n=100) got_random = True if (self._environment.is_space(pos)): Graph.add_node(self, node) self.pos[node] = array(pos) self.ori[node] = ori self.labels[node] = ('C' if node.type == 'C' else "") + str(node.id) logger.debug('Node %d is placed on position %s %s %s' % (node.id, pos, '[energy=%5.3f]' %node.power.energy if node.power.energy != EnergyModel.E_INIT else '', 'Random' if got_random else '')) self.recalculate_edges([node]) else: Node.cid -= 1 logger.error('Given position is not free space. [%s] %s' % (Node.cid, pos)) node = None return node
def modify_avg_degree(self, value): """ Modifies (increases) average degree based on given value by modifying nodes commRange.""" # assert all nodes have same commRange assert allclose([n.commRange for n in self], self.nodes()[0].commRange) #TODO: implement decreasing of degree, preserve connected network assert value + settings.DEG_ATOL > self.avg_degree() # only increment step_factor = 7. steps = [0] #TODO: while condition should call validate while not allclose(self.avg_degree(), value, atol=settings.DEG_ATOL): steps.append((value - self.avg_degree()) * step_factor) for node in self: node.commRange += steps[-1] # variable step_factor for step size for over/undershoot cases if len(steps) > 2 and sign(steps[-2]) != sign(steps[-1]): step_factor /= 2 logger.debug("Modified degree to %f" % self.avg_degree())
def send(self, message): """ Send a message to nodes listed in message's destination field. Note: Destination should be a list of nodes or one node. Update message's source field and inserts in node's outbox one copy of it for each destination. """ message.source = self if not isinstance(message.destination, collections.Iterable): message.destination = [message.destination] for destination in message.destination: logger.debug('Node %d sent message %s.' % (self.id, message.__repr__())) m = message.copy() m.destination = destination self.outbox.insert(0, m)
def modify_avg_degree(self, value): """ Modifies (increases) average degree based on given value by modifying nodes commRange.""" # assert all nodes have same commRange assert allclose([n.commRange for n in self], self.nodes()[0].commRange) #TODO: implement decreasing of degree, preserve connected network assert value + settings.DEG_ATOL > self.avg_degree() # only increment step_factor = 7. steps = [0] #TODO: while condition should call validate while not allclose(self.avg_degree(), value, atol=settings.DEG_ATOL): steps.append((value - self.avg_degree())*step_factor) for node in self: node.commRange += steps[-1] # variable step_factor for step size for over/undershoot cases if len(steps)>2 and sign(steps[-2])!=sign(steps[-1]): step_factor /= 2 logger.debug("Modified degree to %f" % self.avg_degree())
def estimate_position(self, node): TRESHOLD = .1 MAX_ITER = 10 landmarks = [] # get landmarks with hopsize data if self.dataKey in node.memory: landmarks = node.memory[self.dataKey].keys() # calculate estimated distances if len(landmarks) >= 3: landmark_distances = [] landmark_positions = [] try : landmark_distances = [node.memory[self.dataKey][lm][2] * node.memory[self.hopsizeKey] for lm in landmarks] landmark_positions = [array(node.memory[self.dataKey][lm][:2]) for lm in landmarks] except: pass # take centroid as initial estimation pos = average(landmark_positions, axis=0) W = diag(ones(len(landmarks))) counter = 0 dist = lambda x, y: sqrt(dot(x - y, x - y)) while pos.any() != nan: J = array([(lp - pos) / dist(lp, pos) for lp in landmark_positions]) range_correction = array([dist(landmark_positions[li], pos) - landmark_distances[li] for li, lm in enumerate(landmarks)]) pos_correction = dot(linalg.inv(dot(dot(J.T, W), J)), dot(dot(J.T, W), range_correction)) pos = pos + pos_correction logger.debug("Est. %s, %s, %s" %(node.id, pos, pos_correction)) counter += 1 if sqrt(sum(pos_correction ** 2)) < \ TRESHOLD or counter >= MAX_ITER: logger.info("Trilaterate break %s" % counter) break if counter <= MAX_ITER: node.memory[self.positionKey] = pos node.memory['reliable'] = landmark_positions
def receive(self): """ Pop message from inbox but only if it has been there at least one step. Messages should be delayed for one step for visualization purposes. Messages are processed without delay only if they are pushed into empty inbox. So if inbox is empty when push_to_inbox is called _inboxDelay is set to True. This method is used only internally and is not supposed to be used inside algorithms. """ if self._inbox and not self._inboxDelay: message = self._inbox.pop() logger.debug('Node %d received message %s' % (self.id, message.__repr__())) else: message = None self._inboxDelay = False return message
def recalculate_hopsize(self, node): pos = node.memory[self.truePositionKey] try: landmarks_count = len(node.memory[self.dataKey]) except KeyError: pass else: if landmarks_count > 0: dist = lambda x, y: sqrt(dot(x - y, x - y)) dt = 0.0 ht = 0.0 for lp in node.memory[self.dataKey].values(): threshold = FloodingUpdate.lookup.get( lp[2], 0.75) * node.commRange hl = dist(lp[:2], pos) / lp[2] logger.debug("node=%s, hop=%s, threshold=%s, hoplen=%s" % (node.id, lp[2], threshold, hl)) if hl > threshold: # reliable dt += hl ht += lp[2] if ht > 0.01: node.memory[self.hopsizeKey] = dt / ht
def _create_modify_network(self, net=None, step=1): """Helper method for creating new or modifying given network. Arguments: net (int): network to modify, if None create from scratch step: if >0 new network should be more dense for <0 less dense """ if net is None: net = Network(**self.kwargs) for _n in range(self.n_count): node = Node(commRange=self.comm_range, **self.kwargs) net.add_node(node) else: print "here2-" + str(step) if step>0: if len(net)<self.n_max: node = Node(**self.kwargs) net.add_node(node) logger.debug("Added node, number of nodes: %d (%d)" % (len(net), int(self.n_max))) elif not self.comm_range: for node in net.nodes(): node.commRange += step logger.debug("Increased commRange to %d" % node.commRange) else: return None else: print "here3-" + str(self.n_min) if len(net) > self.n_min and len(net) > 1: net.remove_node(net.nodes()[0]) logger.debug("Removed node, nodes left: %d" % len(net)) elif not self.comm_range: if abs(step) >= net.nodes()[0].commRange: step /= 4 for node in net: node.commRange += step logger.debug("Decreased commRange to %d" % net.nodes()[0].commRange) else: return None return net
def receive(self): """ Pop message from inbox but only if it has been there at least one step. Messages should be delayed for one step for visualization purposes. Messages are processed without delay only if they are pushed into empty inbox. So if inbox is empty when push_to_inbox is called _inboxDelay is set to True. This method is used only internally and is not supposed to be used inside algorithms. """ if self._inbox and not self._inboxDelay: message = self._inbox.pop() if not message: return message msg_len = message.message_length() if not self.power.have_energy(): self.n_received_failed_power += 1 logger.debug( "Node %d doesn't have enough energy to receive message [energy=%5.3f]" % (self.id, self.power.energy)) else: self.power.decrease_rx_energy(msg_len) if not message.source: message.source = self p1 = self.network.pos[message.source] p2 = self.network.pos[message.destination] d = sqrt(sum(pow(p1 - p2, 2))) self.distance.append(d) prt = self.network.propagation.get_power_ratio(d=d) self.snr.append(PropagationModel.pw_to_dbm(prt)) rx_ok = self.network.propagation.is_rx_ok(d=d, prt=prt) logger.debug('Node %d received message %s [%d] - %s m (%s)' % (self.id, message.data, msg_len, d, PropagationModel.pw_to_dbm(prt))) if rx_ok: self.n_received += 1 if message.header not in self.memory: self.memory[message.header] = [] self.memory[message.header].append(message.data) else: self.n_received_failed_loss += 1 logger.debug("Receive Failed due to signal loss: %s" % self.network.propagation.get_power_ratio(d=d)) self.energy.append(self.power.energy) else: message = None self._inboxDelay = False return message
def receive(self): """ Pop message from inbox but only if it has been there at least one step. Messages should be delayed for one step for visualization purposes. Messages are processed without delay only if they are pushed into empty inbox. So if inbox is empty when push_to_inbox is called _inboxDelay is set to True. This method is used only internally and is not supposed to be used inside algorithms. """ if self._inbox and not self._inboxDelay: message = self._inbox.pop() if not message: return message msg_len = message.message_length() if not self.power.have_energy(): self.n_received_failed_power += 1 logger.debug("Node %d doesn't have enough energy to receive message [energy=%5.3f]" % (self.id, self.power.energy)) else: self.power.decrease_rx_energy(msg_len) if not message.source: message.source = self p1 = self.network.pos[message.source] p2 = self.network.pos[message.destination] d = sqrt(sum(pow(p1 - p2, 2))) self.distance.append(d) prt = self.network.propagation.get_power_ratio(d=d) self.snr.append(PropagationModel.pw_to_dbm(prt)) rx_ok = self.network.propagation.is_rx_ok(d=d, prt=prt) logger.debug('Node %d received message %s [%d] - %s m (%s)' % (self.id, message.data, msg_len, d, PropagationModel.pw_to_dbm(prt))) if rx_ok: self.n_received += 1 if message.header not in self.memory: self.memory[message.header] = [] self.memory[message.header].append(message.data) else: self.n_received_failed_loss += 1 logger.debug("Receive Failed due to signal loss: %s" % self.network.propagation.get_power_ratio(d=d)) self.energy.append(self.power.energy) else: message = None self._inboxDelay = False return message