float Grid_2D :: get_edge(pair<uint32_t, uint32_t> start, cell_adjacent neighbor) { pair<uint32_t, uint32_t> neighbor_node = neighbor_to_pair(start, neighbor); if(!is_valid_node(start) || !is_neighbor(start, neighbor_node)) { return INFINITY; } uint8_t start_weight = get_weight(start); uint8_t neighbor_weight = get_weight(get_neighbor(start, neighbor)); if(start_weight == INF || neighbor_weight == INF) { return INFINITY; } float edge = start_weight + neighbor_weight; edge /= 2; if(neighbor == TOP_LEFT || neighbor == TOP_RIGHT || neighbor == BOTTOM_LEFT || neighbor == BOTTOM_RIGHT) { edge *= sqrt(2); } return edge; }
pair<uint32_t, uint32_t> Grid_2D :: get_neighbor(pair<uint32_t,uint32_t> node, cell_adjacent neighbor) { pair<uint32_t, uint32_t> neighbor_node = neighbor_to_pair(node, neighbor); if(!is_valid_node(node) || !is_neighbor(node, neighbor_node)) { return node; } return neighbor_node; }
void GrainGrow::executeGrainGrow(int** space, int** old_space){ for (int i = 0; i < HEIGHT; i++) { for (int j = 0; j < WIDTH; j++) { if (old_space[i][j] == 0) { int tab[2]; if (is_neighbor(i, j, tab, old_space)) { space[i][j] = old_space[tab[0]][tab[1]]; } } } } }
bool push_neighbor(queue<string> &Qs, queue<int> &Qi, vector<string> &words, unordered_set<string> &dict, unordered_set<string> &target, string cur, int cur_level){ for(int i = words.size()-1; i >= 0; i--){ if(!is_neighbor(cur, words[i])) continue; if(target.find(words[i]) != target.end()){ return true; } // push to queue and delete in words Qs.push(words[i]); Qi.push(cur_level+1); words.erase(words.begin()+i); } return false; }
TEST(Graph, GetNeighbor) { // Graph G = graphs::RandomGraph(20,0.5); Graph G = graphs::Petersen(); G.add_edges({{1, 0}, {0, 2}, {2, 4}, {3, 5}, {3, 1}, {8, 4}, {1, 9}}); for (auto v : G.vertices()) { for (auto u : G.vertices()) { auto it = G.get_neighbor(u, v); if (G.is_neighbor(u, v)) { ASSERT_EQ(*it, v); } else { ASSERT_EQ(it, G.neighbors(u).end()); } } } auto sortedG = G; sortedG.sort_neighbors(); for (auto v : sortedG.vertices()) { for (auto u : sortedG.vertices()) { auto it = sortedG.get_neighbor(u, v); if (sortedG.is_neighbor(u, v)) { ASSERT_EQ(*it, v); } else { ASSERT_EQ(it, sortedG.neighbors(u).end()); } } } }
// do neighbor discovery check for AOI neighbors //void //vast_dc::check_neighbor_discovery () void vast_dc::post_processmsg () { // // new neighbor notification check // vector<id_t> new_list; // list of new, unknown nodes vector<id_t> hello_list; // list of new nodes to connect vector<id_t> remove_list; // list of nodes to remove from the notified list map<id_t, Msg_NODE>::iterator it = _notified_nodes.begin (); // loop through each notified neighbor and see if it's unknown for (; it != _notified_nodes.end (); ++it) { Msg_NODE &newnode = it->second; Node &node = newnode.node; // check if it's already known // TODO: update_node should have time-stamp check if (is_neighbor (node.id) == true) { _NM_known++; // NOTE: do not update, as an older value might replace what's already // on record, causing larger drift distance //update_node (node); // decrease counter, assuming notification means relevance if (_count_drop[node.id] > 0) _count_drop[node.id]--; // remove this known neighbor from list remove_list.push_back (node.id); } // if the notified node is already outdated, also ignore it else if ((/*_time*/ _net->get_curr_timestamp () - newnode.node.time) > MAX_DROP_COUNT) { remove_list.push_back (node.id); } else { _voronoi->insert (node.id, node.pos); new_list.push_back (node.id); } } // loop through newly inserted nodes and check for relevance int n = new_list.size (); int i; for (i=0; i<n; ++i) { // // we will not connect to a new node if: // 1) the node is irrelevant (outside of AOI) // 2) connection limit has reached // // NOTE that we've added '1' units to the overlap test to avoid roundoff errors if (_voronoi->is_enclosing (new_list[i]) == true || _voronoi->overlaps (new_list[i], _self.pos, (aoi_t)(_self.aoi + _detection_buffer + 1))) { /* if (over_connected () == true) { // shrink the AOI to exclude the new node adjust_aoi (&node.pos); continue; } */ hello_list.push_back (new_list[i]); } } // clear up voronoi first for (i=0; i<n; ++i) _voronoi->remove (new_list[i]); // send HELLO & EN messages to newly discovered nodes n = hello_list.size (); Msg_NODE hello (_self);//, _net->getaddr (_self.id)); // HELLO message to be sent id_t target; for (i=0; i<n; ++i) { target = hello_list[i]; Msg_NODE &newnode = _notified_nodes[target]; /* #ifdef DEBUG_DETAIL char ip[16]; newnode.addr.publicIP.get_string (ip); printf ("[%d] learn about new node [%d] (%s:%d)\n", (int)_self.id, (int)newnode.node.id, ip, (int)newnode.addr.publicIP.port); #endif */ if (insert_node (newnode.node/*, newnode.addr*/) == true) { // send HELLO _net->sendmsg (target, DC_HELLO, (char *)&hello, sizeof (Msg_NODE), true, true); // send EN vector<id_t> &en_list = _voronoi->get_en (target); send_ID (target, DC_EN, en_list); } // remove this node from those being considered remove_list.push_back (target); } // remove notified nodes that are outdated or already known n = remove_list.size (); for (i=0; i<n; ++i) _notified_nodes.erase (remove_list[i]); // NOTE: simply clear out notified nodes gives lower Topology Consistency //_notified_nodes.clear (); // // neighbor discovery check // vector<id_t> notify_list; id_t from_id; #ifdef CHECK_REQNODE_ONLY map<id_t, int>::iterator it2 = _req_nodes.begin (); for (;it2 != _req_nodes.end (); ++it2) { from_id = it2->first; // a node requesting for new neighbor check // might have been disconnected by now, // as we process the request in batch if (is_neighbor (from_id) == false) continue; #else // we check for all known neighbors except myself int num = _neighbors.size (); int idx; for (idx=1; idx<num; ++idx) { from_id = _neighbors[idx]->id; #endif // TODO: clear or new would be faster? notify_list.clear (); map<id_t, int> *known_list = new map<id_t, int>; map<id_t, int>::iterator it; id_t id; int state, known_state; #ifdef CHECK_EN_ONLY // check for only enclosing neighbor vector<id_t> &en_list = _voronoi->get_en (_self.id); int n = en_list.size (); #else // loop through every known neighbor except myself int n = _neighbors.size (); #endif for (int i=0; i<n; ++i) { #ifdef CHECK_EN_ONLY id = en_list[i]; #else id = _neighbors[i]->id; #endif if (id == _self.id || id == from_id) continue; // do a simple test to see if this enclosing neighbor is // on the right side of me if I face the moving node directly // only notify the moving node for these 'right-hand-side' neighbors //if (right_of (id, from_id) == false) // continue; state = 0; known_state = 0; if (_voronoi->overlaps (id, _id2node[from_id].pos, (aoi_t)(_id2node[from_id].aoi + _detection_buffer + 1)) == true) state = state | STATE_OVERLAPPED; if (_voronoi->is_enclosing (id, from_id) == true) state = state | STATE_ENCLOSED; // notify case1: new overlap by moving node's AOI // notify case2: new EN for the moving node if (state != 0) { if ((it = _neighbor_states[from_id]->find (id)) != _neighbor_states[from_id]->end ()) known_state = it->second; // note: what we want to achieve is: // 1. notify just once when new EN is found // 2. notify for new overlap, even if the node is known to be an EN if ((known_state & STATE_OVERLAPPED) == 0 && ((state & STATE_OVERLAPPED) > 0 || ((known_state & STATE_ENCLOSED) == 0 && (state & STATE_ENCLOSED) > 0))) notify_list.push_back (id); // store the state of this particular neighbor known_list->insert (map<id_t, int>::value_type (id, state)); } } //_neighbor_states[from_id]->clear (); delete _neighbor_states[from_id]; _neighbor_states[from_id] = known_list; // notify moving nodes of new neighbors if (_req_nodes.find (from_id) != _req_nodes.end ()) send_nodes (from_id, notify_list); } _req_nodes.clear (); //================================================================================================================= // send out all pending reliable messages _net->flush (); } /* int vast_dc::recv (id_t target, char *buffer) { if (_joined == false) { printf ("[%d] attempt to receive before joined successfully\n", _self.id); return 0; } if (_id2msg.find (target) == _id2msg.end ()) return 0; netmsg *queue = _id2msg[target]; netmsg *msg; queue = queue->getnext (&msg); // update the mapping to queue if (queue == NULL) _id2msg.erase (target); else _id2msg[target] = queue; // copy the msg into buffer int size = msg->size; memcpy (buffer, msg->msg, size); delete msg; return size; } */ // // private methods // bool vast_dc::insert_node (Node &node, Addr *addr) { // check for redundency if (is_neighbor (node.id)) return false; // avoid self-connection // note: connection may already exist with remote node, in which case the // insert_node process will continue (instead of aborting..) if (node.id != _self.id && !(_net->is_connected (node.id))) { int result = (addr != NULL ? _net->connect (*addr) : _net->connect (node.id)); if (result == (-1)) return false; } _voronoi->insert (node.id, node.pos); _id2node[node.id] = node; _id2vel[node.id] = 0; _neighbors.push_back (&_id2node[node.id]); _neighbor_states[node.id] = new map<id_t, int>; _count_drop[node.id] = 0; return true; } /* // overloaded version for the node's address is prefetched bool vast_dc::insert_node (Node &node, Addr &addr) { // check for redundency if (is_neighbor (node.id)) return false; if ( node.id != _self.id && !(_net->is_connected (node.id)) ) if (_net->connect (addr) == (-1)) return false; return _post_insert_node (node); } bool vast_dc::insert_node (Node &node) { // check for redundency if (is_neighbor (node.id)) return false; // avoid self-connection // note: connection may already exist with remote node, in which case the // insert_node process will continue (instead of aborting..) if ( node.id != _self.id && !(_net->is_connected (node.id)) ) if (_net->connect (node.id) == (-1)) return false; return _post_insert_node (node); } bool vast_dc::_post_insert_node (Node &node) { _voronoi->insert (node.id, node.pos); _id2node[node.id] = node; _id2vel[node.id] = 0; _neighbors.push_back (&_id2node[node.id]); _neighbor_states[node.id] = new map<id_t, int>; _count_drop[node.id] = 0; return true; } */ bool vast_dc::delete_node (id_t id, bool disconnect) { // NOTE: it's possible to remove self or EN, use carefully. // we don't check for that to allow force-remove in // the case of disconnection by remote node, or // when leaving the overlay (removal of self) if (is_neighbor (id) == false) return false; #ifdef DEBUG_DETAIL printf ("[%lu] disconnecting [%lu]\n", _self.id, id); #endif if (disconnect == true) _net->disconnect (id); _voronoi->remove (id); vector<Node *>::iterator it = _neighbors.begin(); for (; it != _neighbors.end (); it++) { if ((*it)->id == id) { _neighbors.erase (it); break; } } _id2node.erase (id); _id2vel.erase (id); delete _neighbor_states[id]; _neighbor_states.erase (id); _count_drop.erase (id); return true; } bool vast_dc::update_node (Node &node) { if (is_neighbor (node.id) == false) return false; // only update the node if it's at a later time if (_id2node[node.id].time <= node.time) { // calculate displacement from last position double dis = _id2node[node.id].pos.dist (node.pos); _voronoi->update (node.id, node.pos); _id2node[node.id].update (node); _id2vel[node.id] = dis; } return true; } // send node infos (NODE message) to a particular node // 'list' is a list of indexes to _neighbors void vast_dc::send_nodes (id_t target, vector<id_t> &list, bool reliable) { int n = list.size (); if (n == 0) return; // TODO: sort the notify list by distance from target's center _buf[0] = (unsigned char)n; char *p = _buf+1; #ifdef DEBUG_DETAIL printf (" aoi: %d ", (aoi_t)(_id2node[target].aoi + _detection_buffer)); #endif VAST::Msg_NODE node; for (int i=0; i<n; ++i, p += sizeof (Msg_NODE)) { node.set (_id2node[list[i]]);//, _net->getaddr (list[i])); /* #ifdef DEBUG_DETAIL char ip[16]; node.addr.publicIP.get_string (ip); printf ("[%d] (%s:%d) ", (int)list[i], ip, (int)node.addr.publicIP.port); #endif */ memcpy (p, (char *)&node, sizeof (Msg_NODE)); } #ifdef DEBUG_DETAIL printf ("\n"); #endif // check whether to send the NODE via TCP or UDP _net->sendmsg (target, DC_NODE, _buf, 1 + n * sizeof (Msg_NODE), reliable, true); }
// process a single message in queue bool vast_dc::handlemsg (VAST::id_t from_id, msgtype_t msgtype, timestamp_t recvtime, char *msg, int size) { #ifdef DEBUG_DETAIL printf ("%4d [%3d] processmsg from: %3d type: (%2d)%-12s size:%3d\n", (int)_net->get_curr_timestamp (), (int)_self.id, (int)from_id, msgtype, (msgtype>=10 && msgtype<=DC_UNKNOWN)?VAST_DC_MESSAGE[msgtype-10]:"UNKNOWN", size); #endif // should do like this way? if (_joined == S_INIT) { // if I'm not suppose to join, any VAST message will incur disconnect the node // protential BUG: any side effects? if (msgtype >= DC_QUERY && msgtype < DC_UNKNOWN) { // if a query message, send it back to prevent other nodes fail to join if (msgtype == DC_QUERY) _net->sendmsg (from_id, msgtype, msg, size); if (_net->is_connected (from_id)) _net->disconnect (from_id); } return false; } else if (_joined == S_JOINING && msgtype != DC_NODE) return false; switch ((VAST_DC_Message)msgtype) { case DC_QUERY: if (size == sizeof (Msg_QUERY)) { // to prevent gateway server from over-connection if (_self.id == NET_ID_GATEWAY) _net->disconnect (from_id); Msg_QUERY n (msg); Node &joiner = n.node; VAST::id_t closest_id = _voronoi->closest_to (joiner.pos); // forward the request if a more approprite node exists if (_voronoi->contains (_self.id, joiner.pos) == false && closest_id != _self.id && closest_id != from_id) { _net->sendmsg (closest_id, DC_QUERY, msg, size, true, true); } else { // I am the acceptor, send back initial neighbor list vector<VAST::id_t> list; // insert first so we can properly find joiner's EN // TODO: what if joiner exceeds connection limit? // should remove closest to AOI // insert_node (joiner, &n.addr); int size = _neighbors.size (); for (int i=0; i<size; ++i) { if (_neighbors[i]->id == joiner.id) continue; // send only relevant neighbors if (_voronoi->overlaps (_neighbors[i]->id, joiner.pos, joiner.aoi) || _voronoi->is_enclosing (_neighbors[i]->id, joiner.id)) list.push_back (_neighbors[i]->id); } send_nodes (joiner.id, list, true); } } break; case DC_HELLO: if (size == sizeof (Msg_NODE)) { Msg_NODE newnode(msg); if (is_neighbor (from_id)) update_node (newnode.node); else { // accept all HELLO request // we assume over-connections can be taken care // later by adjust_aoi mechanism insert_node (newnode.node);//, newnode.addr); } } break; case DC_EN: if ((size-1) % sizeof(VAST::id_t) == 0) { // ignore EN request if not properly connected if (is_neighbor (from_id) == false) break; int n = (int)msg[0]; char *p = msg+1; // BUG: potential memory leak for the allocation of map? map<VAST::id_t, int> *list = new map<VAST::id_t, int>; // list of EN received vector<VAST::id_t> missing; // list of missing EN ids vector<VAST::id_t> &en_list = _voronoi->get_en (_self.id); // list of my own EN int i; // create a searchable list of EN (BUG, mem leak for insert?) for (i=0; i<n; ++i, p += sizeof (VAST::id_t)) list->insert (map<VAST::id_t, int>::value_type (*(VAST::id_t *)p, STATE_OVERLAPPED)); // store as initial known list (clear necessary to prevent memory leak?) // csc 20080305: unnecessary, destructor should do it while deleting //_neighbor_states[from_id]->clear (); delete _neighbor_states[from_id]; _neighbor_states[from_id] = list; int en_size = en_list.size (); for (i=0; i<en_size; ++i) { // send only relevant missing neighbors if (list->find (en_list[i]) == list->end () && en_list[i] != from_id && _voronoi->overlaps (en_list[i], _id2node[from_id].pos, _id2node[from_id].aoi)) missing.push_back (en_list[i]); } send_nodes (from_id, missing); } break; case DC_MOVE: case DC_MOVE_B: if (size == sizeof (Node)) { Node *node = (Node *)msg; // if the remote node has just been disconnected, // then no need to process MOVE message in queue if (update_node (*node) == false) break; // records nodes requesting neighbor discovery check if (msgtype == DC_MOVE_B) _req_nodes[from_id] = 1; //req_nodes.push_back (from_id); /* // prevent incorrect judgement when later I become a BN else _neighbor_states[from_id]->clear (); */ } break; case DC_NODE: if ((size-1) % sizeof (Msg_NODE) == 0) { int n = (int)msg[0]; char *p = msg+1; Msg_NODE newnode; // new node discovered if (_joined < S_JOINING) break; // TODO: find a cleaner way than to reset everytime _joined = S_JOINED; // store each node notified, we'll process them later in batch int i; bool store; map<VAST::id_t, Msg_NODE>::iterator it; for (i=0; i<n; ++i, p += sizeof (Msg_NODE)) { _NM_total++; memcpy (&newnode, p, sizeof (Msg_NODE)); store = true; it = _notified_nodes.find (newnode.node.id); if (it != _notified_nodes.end ()) { _NM_known++; // potential BUG: // NOTE: we're using time to decide if using a newer one to replace // an existing notified node, however this might give // false prefererence if remote nodes' clocks are not // well-synchronized if (newnode.node.time < (it->second).node.time) store = false; } if (store) { // store the new notified node with my own time // this is to ensure time-based disposal can work properly newnode.node.time = _net->get_curr_timestamp (); //_time; _notified_nodes[newnode.node.id] = newnode; } /* if (_notified_nodes.find (newnode.node.id) != _notified_nodes.end ()) { _NM_known++; if (_notified_nodes[newnode.node.id].node.time < newnode.node.time) _notified_nodes[newnode.node.id] = newnode; } else _notified_nodes[newnode.node.id] = newnode; */ // notify network knowledge source of IP address // TODO: queue all nofities in the same step vector<VAST::id_t> idlist; idlist.push_back (newnode.node.id); _net->notify_id_mapper (from_id, idlist); } } break; case DC_OVERCAP: if (size == 0) { if(is_neighbor (from_id) == false) break; // remote node has exceeded its capacity, // we need to shrink our own AOI adjust_aoi (&_id2node[from_id].pos); } break; /* case DC_PAYLOAD: { // create a buffer netmsg *newnode = new netmsg (from_id, msg, size, msgtype, recvtime, NULL, NULL); // put the content into a per-neighbor queue if (_id2msg.find (from_id) == _id2msg.end ()) _id2msg[from_id] = newnode; else _id2msg[from_id]->append (newnode, recvtime); } break; */ case DISCONNECT: if ((size-1) % sizeof (id_t) == 0) { int n = msg[0]; char *p = msg+1; id_t id; for (int i=0; i<n; ++i, p+=sizeof (id_t)) { memcpy (&id, p, sizeof (id_t)); // see if it's a remote node disconnecting me if (id == _self.id) delete_node (from_id, false); /* // delete this node from list of known neighbors else { map<id_t, int> *list; map<id_t, int>::iterator it; if (_neighbor_states.find (from_id) != _neighbor_states.end ()) { list = _neighbor_states[from_id]; if ((it = list->find (id)) != list->end ()) list->erase (it); } } */ } } // allow other handlers to handle the DISCONNECT message return false; default: #ifdef DEBUG_DETAIL // throw to additional message handler, if it exists ERROR_MSG_ID (("unknown message")); #endif return false; } return true; }
void fragment_identifier(axl_network *mysys, int clustering_radio, int type_search, int opinion_links_included) { /* ================================================= Fragment identifier: It takes as argument an axelrod network, and puts into vector labels an identifier of each agent. If two agents share an equal label it means that they belong from the same cluster. Degree[i] is the degree of the node i. Neighbors[i] are the neighbors of node i, from 0 to degree[i]. ==================================================*/ int i, j, k; int node1, node2; int *ordering; int n = mysys->nagents; ordering = (int *)malloc( n * sizeof(int)); // Initilization of the vector labels and ordering // Ordering vector puts the nodes with the same label together for(i = 0; i < n; i++) { mysys->agent[i].label = i; ordering[i] = i; } j = 0; for(i = 0; i < n; i++) { // Node 1 is the node in the i'th place of ordering node1 = ordering[i]; if(j == i) j += 1; // j is the place where we are in the ordering vector, allways a step after i // k is the index which we use to go over the vector ordering. It allways starts from the j'th place k = j; while(k < n) { // Node 2 is the node which we compare with node 1 node2 = ordering[k]; if(((is_neighbor(mysys->agent[node1], node2, opinion_links_included,type_search)) == 1) && (is_same_state(mysys->agent[node1], mysys->agent[node2], clustering_radio, type_search) == 1)) // It means: if node2 is a neighbor of node1 and they have the same state, so... { // Label of node 2 becomes the same as the node 1's label mysys->agent[node2].label = mysys->agent[node1].label; // We put the node 2 in the j'th place swap(ordering + k, ordering + j); // The new place in the ordering vector is the following j++; } k++; } } free(ordering); return; }