Last active
April 14, 2021 20:04
-
-
Save cppcooper/833a633ad472b29ab5b96b14d517d1c2 to your computer and use it in GitHub Desktop.
[C++] graphs? partial copy of header
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static void DepthFirstProcNodes(JTMetaNode* jt_node, std::function<void(JTMetaNode*)> procedure){ | |
/** Process by depth first | |
* 1. loop over all edges in this node | |
* 2. for every edge to a child (ie. edge.Right != bn_node) | |
* - put this child node on the top of the stack | |
* - go back to step 1 for the node from the top of the stack | |
* 3. run the provided procedure on the node | |
* 4. unwind stack and continue at step 2 for the node on the stack*/ | |
for(auto jt_iter = jt_node->Edges.begin(); jt_iter != jt_node->Edges.end(); ++jt_iter) { | |
if(jt_node != jt_iter->Right) { | |
DepthFirstProcNodes(jt_iter->Right,procedure); | |
/** We may be creating an undirected graph but | |
* this sort of thing helps recurse the graph. */ | |
} | |
} | |
procedure(jt_node); | |
} | |
void TriangulateGraph(){ | |
/** | |
* 1. Calculate edges to add for each node's cluster | |
* 2. Select a node | |
* - must add the least number of edges in subsequent steps | |
* - the node with the lowest weight out of least edge heavy | |
* 3. Cluster this node, and its neighbours | |
* 4. Add missing edges connecting nodes in this cluster | |
* 5. "Remove this node from the copy graph" | |
* - Implemented as a hashed set of removed nodes, which is checked against before processings an edge | |
* | |
* notes: | |
* the selected node is removed from copy | |
* new edges are added to both graphs | |
* the non-copy will be triangulated | |
* the copy will be empty | |
* | |
* */ | |
std::multimap<int,ClusterJob> cluster_weights; | |
auto get_weight = [&](JTMetaNode* node){ | |
int edge_count = 0; | |
ClusterJob job; | |
job.owner = node; | |
for(int i = 0; i+1 < node->Edges.size(); ++i){ | |
auto node1 = (node->Edges.begin()+i)->GetOther(node); | |
for(int j = 1; j < node->Edges.size(); ++j){ | |
auto node2 = (node->Edges.begin()+j)->GetOther(node); | |
auto ident = node1->identity | node2->identity; | |
if(!node1->containsEdge(ident)){ | |
/// We would need to check that this edge isn't already added | |
/// but, the loops should only make unique pairs. | |
edge_count++; | |
JTMetaEdge edge; | |
edge.identity = ident; | |
edge.Left = node1; | |
edge.Right = node2; | |
job.edges_to_add.push_back(edge); | |
} | |
} | |
} | |
job.weight = edge_count; | |
cluster_weights.emplace(job.weight,job); | |
}; | |
/// Populates cluster_weights map | |
DepthFirstProcNodes(root,get_weight); | |
/// Connect cluster nodes - ordered least to greatest weight | |
std::uset<JTMetaNode*> removed_list; | |
for(auto pair : cluster_weights){ | |
for(auto edge : pair.second.edges_to_add){ | |
// if edge.Left or edge.Right are not supposed to be in the graph, we skip | |
if(!removed_list.contains(edge.Left) && !removed_list.contains(edge.Right)) { | |
// if our left and right nodes are already connected, we skip | |
if (!edge.Left->containsEdge(edge.identity) && !edge.Right->containsEdge(edge.identity)) { | |
edge.Left->Edges.push_back(edge); | |
edge.Right->Edges.push_back(edge); | |
} | |
} | |
} | |
// Remove the neighborhood's owner | |
removed_list.emplace(pair.second.owner); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment