Skip to content

Instantly share code, notes, and snippets.

@cppcooper
Last active April 14, 2021 20:04
Show Gist options
  • Save cppcooper/833a633ad472b29ab5b96b14d517d1c2 to your computer and use it in GitHub Desktop.
Save cppcooper/833a633ad472b29ab5b96b14d517d1c2 to your computer and use it in GitHub Desktop.
[C++] graphs? partial copy of header
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