I managed to figure out the answer to this question as I was writing it. Keeping it posted to hopefully aide future devs that run into similar issue.
Here's a quick rundown:
I have a directed, weighted map class.
I keep track of all my nodes in: vector<Node> nodes;
I keep track of all the nodes' adjacent nodes in map<Node, <map<Node, int>> connections
When I try doing a traversal through the Graph and I reach a node that does not have any adjacent nodes it will crash the program because my map throws out_of_range exception.
After looking online I see someone has the solution of using this line of code when they are adding nodes: (void) connections[node];. If I remove this line of code, I get the out_of_range exception from the map class's .at() function, but with this line of code, it somehow avoids that exception.
My Question: What is the line of code doing that avoids the exception from being thrown?
My best guess right now is that the line of code is somehow creating an empty adjacency list and my for-each loop doesn't get the exception
set<Node> nodes; // {n1, n2...nn}
map<Node, map<Node, int>> connections; //Connections between the nodes and their weights
//Add node to graph
void add(Node node) {
nodes.insert(node); //add to node list
(void) connections[node]; //This is the magic line!!
}
bool DFS(N start, N target) {
for (Node node : nodes) {
//This for-each loop crashes when the node in the .at() doesn't exist in the connections map
for (pair<N, int> connectedNode : connections.at(node)) {
if (target == connectedNode.first) {
return true;
}
}
}
return false;
}
As I was writing the question I was able to answer my own question. Love a good Rubber Ducky moment. Hopefully, this question can aide future devs who also miss the very basic answer to this question.
In stl::map the [ ] operator will get a reference to the value of the key inside the [ ] if it exists, if it doesn't exist it creates one.
So in the add(Node node) function the (void)connections[node] was actually creating the node in the adjacency map.
The (void) before the line is telling the compiler to ignore any warnings about this because it's technically an incomplete line of code (according to the compiler). Read more about the meaning of (void) here
Related
About the project:
I am working on an Opengl ray-tracer, which is capable of loading obj files and ray-trace it. My application loads the obj file with assimp and then sends all of the triangle faces (the vertices and the indices) to the fragment shader by using shader storage objects. The basic structure is about to render the results to a quad from the fragment shader.
When I load bigger obj-s (more than 100 triangles), it took so much time for the computer to do the intersections, so I started creating a BVH-tree to speed up the process. My BVH splits up the space into two axis-aligned-bounding-boxes recursively based on the average median of the triangles faces contained in the AABB.
I succeed to build the BVH tree structure (on CPU) and now I want to convert it to a simple array, then send it to fragment shader (to a shader storage buffer).
Here is the method responsible for converting the BVH root node into an array:
BvhNode bvhNode; //global variable
BvhNode* putNodeIntoArray() {
int size=bvhNode.getNumberOfNodes();
BvhNode nodesArray[size];
int current_index = 0;
vector<BvhNode> tempNodes;
tempNodes.push_back(bvhNode);
BvhNode current_node;
while (!tempNodes.empty()) {
current_node = tempNodes.at(0);
tempNodes.erase(tempNodes.begin());
nodesArray[current_index] = current_node;
if(!current_node.isLeaf)
{
tempNodes.push_back(current_node.children.at(0)); // Segmentation error occurs here!
tempNodes.push_back(current_node.children.at(1));
}
current_index++;
}
return nodesArray;
}
About the problem:
I don't know why, but it gives me a segmentation error, when I want to push_back the first child to the tempNodes vector (the exact place can be seen by the comment above). It seems to me current_node.children.at(0) does not exist, but actually it exists according to the debugger.
I tried to write reference (&) operator: tempNodes.push_back(¤t_node.children.at(0));, but in this case it is giving me weird coordinates to the objects. I tried to define the variables in the function as globals - trying to avoid scope problems -, as well as defining the current_node variable as a pointer. Unfortunately none of them gave me better results.
Here is my BvhNode class, if it helps:
class BvhNode {
public:
BBox bBox;
int depthOfNode;
vector<BvhNode> children;
int order;
bool isLeaf;
bool createdEmpty = false;
vector<glm::vec3> primitiveCoordinates;
BvhNode() {}
BvhNode(BvhNode *pNode) {}
BvhNode(vector<glm::vec3> &primitiveCoordinates) {
this->primitiveCoordinates = primitiveCoordinates; }
void buildTree(vector<glm::vec3>& indicesPerFaces, int depth) {... }
Update 1:
I updated the method according to the comments. So I changed the type of the returning value to vector insted of BvhNode*. The algorithm works fine until it reaches the process of putting the leaf nodes into the std::vector. So when it starts to putting the last level of the graph to the vector, it gives me this error:
Program received signal SIGSEGV, Segmentation fault.
0x00007fbda4d69c01 in __GI___libc_free (mem=0x555be3a9dba0) at malloc.c:3123
3123 malloc.c: No such file or directory.
I managed to put seven nodes (meaning all depth levels of the tree except the level of leaves) into the vector. I also tried to run valgring, but actually valgrind does not give me any error, not like in CLion.
This is my modified method. I commented the place of segmentation fault and the fixes.
BvhNode bvhNode;
vector<BvhNode> putNodeIntoArray() {
int size=bvhNode.getNumberOfNodes();
// FIX: I modified the array into an std::vector
vector<BvhNode> nodesArray(size);
int current_index = 0;
vector<BvhNode> tempNodes;
tempNodes.push_back(bvhNode);
BvhNode current_node;
while (!tempNodes.empty()) {
current_node = tempNodes.front();// Segmentation error!!
tempNodes.erase(tempNodes.begin());
nodesArray.at(current_index)=current_node;
nodesArray.at(current_index).children.clear();
// FIX: I also modified this not to iterate through leaves' children, because they don't exist.
if(!current_node.children.empty())
{
tempNodes.push_back(current_node.children.at(0));
tempNodes.push_back(current_node.children.at(1));
}
current_index++;
}
return nodesArray;
}
Your vectors store the BvhNodes everywhere by value.
This means that every time you push_back a node, its copy constructor is called, which in turn copies the children vector member inside the node, which copies its own elements etc.
This basically results in complete subtrees being copied/freed every time you insert or erase a node.
This in turn can result in memory fragmentation, which can eventually cause a vector reallocation to fail and cause a segfault.
Without the full code, I can recommend these 2 things:
Store the children as (smart) pointers instead of by value
Create a custom allocator for the vectors to enable a more fine-grained debugging, and check for allocation failures
Actually the problem was in the creation of the Bvh Tree. Because I wanted to reach the children in the form of 2*i+1 and 2*i+2, I was using a method to make the binary tree full (every level has maximum number of nodes). In this method I had to push empty nodes to the tree.
I was creating the empty node like this:
BvhNode emptyNode;
instead of this:
BvhNode *emptyNode = new BvhNode();
So, when the method finished, the lifetime of the emptyNode was ended. And that caused the segmentation fault.
Moreover, there was also a problem, that I stored the BvhNode by value during the creation of the flat binary tree as Balázs Kovacsis pointed out. This option made the app much slower and it was another potential place to cause segmentation fault.
I have a program that needs to detect cycles (and nodes that are members of that cycle) in directed graphs. To do this, I use LLVM's strongly-connected components algorithm. It's pretty easy to use and it does pretty much what it should:
vector<vector<PreAstBasicBlock*>> stronglyConnectedComponents;
for (auto iter = scc_begin(&function); iter != scc_end(&function); ++iter)
{
if (iter.hasLoop())
{
stronglyConnectedComponents.push_back(*iter);
}
}
This correctly identifies simple SCCs like this simple one:
This is great, but I'd love to know when I have strongly-connected components within each larger strongly-connected components. For instance, this is identified as a single SCC:
That's absolutely correct, since every node in that graph is reachable starting from any other node. However, B⇄C has the additional property that it is independent of the D→A back-edge. It is an SCC by itself and it has a single entry node and a single exiting node: I could replace it with one single node and I wouldn't have edges poking in or out of its conceptual middle.
How can I find these smaller strongly-connected components in the strongly-connected components?
So I was trying to craft a nice response / things you can do with more functions available to you, but was working on it offline and my computer crashed :(.
I've recreated the core of what I was trying to say, that only solves your immediate problem / example, in pseudo-code using a nonexistent GetConnectedComponents(...) helper function whose idealized behavior you can hopefully understand from context:
bool HasConnectedSubgraph(Graph& entire_graph) {
for (const auto& connected_subgraph : GetConnectedComponents(entire_graph)
for (const auto& connected_node : connected_subgraph) {
local_copy = connected_subgraph;
local_copy.erase(std::remove_if(local_copy.begin(), local_copy.end(),
[&](const Node& n) {return n == connected_node}) , local_copy.end());
if (!GetConnectedComponents(local_copy).empty()) {
return true;
}
}
}
return false;
}
This certainly isn't efficient or pretty, but should be enough to springboard your thoughts on the problem.
I'm working on an AVL Tree Project (almost finished after lots of hours of programming) and I wonder if it's possible to keep data from the calling recursion. This is the code:
node* previous;
//Visits the nodes by level recursively (post-order traversal), so that it can calculate the balance of each node (updates heights when deleting a node with two children)
void AVLTree::updateTreeHeights(node *ptr)
{
if(ptr==root)
previous=root;
if(ptr==NULL)
return;
updateTreeHeights(ptr->leftChild);
updateTreeHeights(ptr->rightChild);
if(ptr->leftChild==NULL && ptr->rightChild==NULL)
{
ptr->heightL=ptr->heightR=0;
}
else if(ptr->leftChild==NULL)
{
ptr->heightR=max(ptr->rightChild->heightL,ptr->rightChild->heightR)+1;
ptr->heightL=0;
}
else if(ptr->rightChild==NULL)
{
ptr->heightL=max(ptr->leftChild->heightL,ptr->leftChild->heightR)+1;
ptr->heightR=0;
}
else
{
ptr->heightL=max(ptr->leftChild->heightL,ptr->leftChild->heightR)+1;
ptr->heightR=max(ptr->rightChild->heightL,ptr->rightChild->heightR)+1;
}
ptr->balance=ptr->heightR-ptr->heightL;
if(ptr->balance>1)
balanceTree(ptr,previous,ptr->rightChild);
else if(ptr->balance<-1)
balanceTree(ptr,previous,ptr->leftChild);
}
Here's what I want! I want to keep the ptr value from the calling recursion and save it to the gloabal variable named previous (it's not necessery to be global, but I figured that it must be the only way). For example if ptr points at number 20 and then we call the recursive function for ptr's leftChild (e.g. updateTreeHeights(ptr->leftChild);) I want to keep number 20 (previous=ptr;). Is it possible somehow? I'm not really good with recursion! (Don't tell! :P )
I don't see why not. You can make a global variable and then just copy it over from updateTreeHeights. Just keep a look out for making sure the copy happens only once, and also by doing previous=ptr previous will be pointing to the entire node. So you might have to dive a little deeper in the node to get the date you want.
Let Action be a class with a is_finished method and a numeric tag property.
Let this->vactions be a std::vector<Action>
The intent is to iterate the vector and identify those Actions who are finished,
store their tags in a std::vector<unsigned int> and delete the actions.
I tried to play with lambdas and a little and came up with a little
code that read nicely but caused memory corruptions. The "extended" version,
on the other hand, works as expected.
I suspect foul play in the remove_if part, but for the life of me I can't figure
out what's wrong.
Here's the example code.
This causes memory corruptions
std::vector<unsigned int> tags;
auto is_finished=[p_delta](Action& action) -> bool {return action.is_finished();};
//This is supposed to put the finished actions at the end of the vector and return
//a iterator to the first element that is finished.
std::vector<Action>::iterator nend=remove_if(this->vactions.begin(), this->vactions.end(), is_finished);
auto store_tag=[&tags](Action& action)
{
if(action->has_tag())
{
tags.push_back(action->get_tag());
}
};
//Store the tags...
for_each(nend, this->vactions.end(), store_tag);
//Erase the finished ones, they're supposed to be at the end.
this->vaction.erase(nend, this->vaction.end());
if(tags.size())
{
auto do_something=[this](unsigned int tag){this->do_something_with_tag(tag);};
for_each(tags.begin(), tags.end(), do_something);
}
This, on the other side, works as expected
std::vector<Action>::iterator ini=this->vactions.begin(),
end=this->vactions.end();
std::vector<unsigned int> tags;
while(ini < end)
{
if( (*ini).is_finished())
{
if((*ini).has_tag())
{
tags.push_back((*ini).get_tag());
}
ini=this->vaction.erase(ini);
end=this->vaction.end();
}
else
{
++ini;
}
}
if(tags.size())
{
auto do_something=[this](unsigned int tag){this->do_something_with_tag(tag);};
for_each(tags.begin(), tags.end(), do_something);
}
I am sure there's some rookie mistake here. Can you help me spot it?.
I thought that the for_each could be updating my nend iterator but found
no information about it. What if it did? Could the vector try to erase beyond the "end" point?.
std::remove_if does not preserve the values of the elements that are to be removed (See cppreference). Either get the tag values before calling remove_if - as you do in the second case - or use std::partition instead.
Ok I have been working on a class to iterate through all nodes in an html doc and return the data that I need. This is very simple and I have achieved this in Bash but now I am trying to port the same to C++.
I started with the example on the libxml site but I have stepped through this function node by node and I can't understand how it is working.
Here is the function:
static void
print_element_names(xmlNode * a_node)
{
xmlNode *cur_node = NULL;
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
printf("node type: Element, name: %s\n", cur_node->name);
}
print_element_names(cur_node->children);
}
}
So basically, this function takes a node assigns it to a pointer, and starts to loop through all sibling nodes, but if the current node has children, it calls the function and start over on that child node. This is all very understandable.
So it drives down the doc structure, but how does it navigate back up the structure?
Does xmlNode->children return the next parent node when it is found NULL? As far as I can tell, this is not true, but I just can't figure out how this is working.
I successfully created a class to do what I want, but it is so much more complex than this and about 10 lines longer. I actually had to check if the next node was null and either navigate down if it has children or navigate back up and to the next node if it didn't.
This example is much simpler and I would like to understand how to make my code better.
So it drives down the doc structure, but how does it navigate back up the structure?
What you have posted is a recursive function. From the nature of your question, I'm assuming you don't quite understand what recursion is/how it works. A quick google search should give you some good information/examples.
Does xmlNode->children return the next parent node when it is found NULL?
I am assuming that xmlNode->children returns a pointer to a linked list containing all children of the current node. If the current node has no children, it would probably return NULL.
This example is much simpler and I would like to understand how to make my code better.
I am assuming the class you wrote was purely iterative. Recursive functions can greatly simplify code, but performance wise they can cause issues on larger data sets. I would definitely recommend reading up on them; they can be quite fun.
Solving the problem iteratively is essentially a tree traversal. You will need a stack to accomplish this. The stack can probably be most easily implemented as a singly-linked-list.
// interface to be implemented
typedef void* Stack;
Stack stack_new(); // creates a new stack
void stack_add(Stack stack, xmlNode *element); // adds an element to the stack
int stack_size(); // returns the number of elements currently in the stack
xmlNode* stack_remove(Stack stack); // pops an element from the stack
void stack_free(Stack stack); // frees up resources used by the stack
// printing code
static void print_element_names(xmlNode *a_node)
{
Stack stack = stack_new();
stack_add(stack, a_node);
while(stack_size(stack))
{
xmlNode *cur_node = stack_remove(stack);
if(cur_node->children) stack_add(cur_node->children);
xmlNode *iter_node = NULL;
for (iter_node = cur_node; iter_node; iter_node = iter_node->next)
{
if (iter_node->type == XML_ELEMENT_NODE)
printf("node type: Element, name: %s\n", iter_node->name);
}
}
stack_free(stack);
}