OpenMesh skipping circulators - openmesh

OpenMesh has its skipping iterators which skips elements marked for deletion. Is there an equivalent in circulators? I'm thinking circulators which treat mesh elements marked deleted as if they were not there any more.
Note that this is not as simple as using the existing circulators and testing whether an element was marked for deletion because this does not take into account the changes in topology (neighboring elements, connected elements, etc) that would result from the deletion.

Circulators use the mesh connectivity (as described here) to walk around the neighborhood of an element. When mesh elements are deleted using the usual API (e.g. delete_vertex, delete_edge, delete_face), those elements are marked as deleted and the connectivity is updated such that deleted elements are no longer reachable. By construction, circulators cannot reach deleted elements and therefore no distinction between skipping / non-skipping circulators is necessary.
Iterators, in contrast to circulators, don't use the mesh connectivity but simply iterate over a list of all elements (which can contain deleted elements until garbage_collection is called). Therefore, skipping / non-skipping variants of iterators exist, that either exclude or include deleted elements.

Actually, it looks like OpenMesh does precisely this by default. Elements marked for deletion are considered as if they were not present for the circulators.

Related

Will key in the index be removed after deletion in B Plus tree?

I'm a little confused with the deletion in B+ tree. I searched a lot in Google and find that there are two implementation when the key you want to delete appears in the index:
Delete the key in the index
Keep the key in the index
Algorithm from https://www.javatpoint.com/b-plus-tree-deletion uses the first way.
Algorithm from https://www.cs.princeton.edu/courses/archive/fall08/cos597A/Notes/BplusInsertDelete.pdf uses the second way.
So I really want to know which one is right.
But I'm more inclined to take that as an undefined behavior. At this point, could someone help me figure out the advantage and disadvantage between them? And how to choose between them?
Thanks in advance.
Both methods are correct.
The difference that you highlight is not so much in deleting/not-deleting internal keys, but in updating/not-updating them.
Obviously, when you delete a value (i.e. a key in a leaf node), the b-plus-tree property is not violated: all child values are still within the range dictated by the parent information. You can never break this range-rule by merely removing a value from a leaf. This rule is also still valid when you update the internal key(s) in the path to that leaf (according to method 1), which is only necessary when the deleted value was the left-most one in its leaf.
Note that the two methods may produce quite different trees after a long sequence of the same operations (insert, delete).
But on average the second method will have slightly less work to do. This difference is not significant though.

How to implement a collection that supports real-time filtering?

I want to implement a mutable sequential collection FilteredList that wraps another collection List and filters it based on a predicate.
Both the wrapped List and the exposed FilteredList are mutable and observable, and should be synchronized (so for example, if someone adds an element to List that element should appear in the correct position in FilteredList, and vice versa).
Elements that don't satisfy the predicate can still be added to FilteredList, but they will not be visible (they will still appear in the inner list).
The collections should support:
Insert(index,value) which inserts an element value at position index, pushing elements forward.
Remove(index) which removes the element at position index, moving all proceeding elements back.
Update(index, value), which updates the element at position index to be value.
I'm having trouble coming up with a good synchronization mechanism.
I don't have any strict complexity bounds, but real world efficiency is important.
The best way to avoid synchronization difficulties is to create a data structure that doesn't need them: use a single data structure to present the filtered and unfiltered data.
You should be able to do that with a modified skip list (actually, an indexable skip list), which will give you O(log n) access by index.
What you do is maintain two separate sets of forward pointers for each node, rather than just one set. The one set is for the unfiltered list, as in the normal skip list, and the other set is for the filtered list.
Adding to or removing from the list is the same for the filtered and unfiltered lists. That is, you find the node at index by following the appropriate filtered or unfiltered links, and then add or remove the node, updating both sets of link pointers.
This should be more efficient than a standard sequential list, because insertion and removal don't incur the cost of moving items up or down to make a hole or fill a gap; it's all done with references.
It takes a little more space per node, though. On average, skip list requires two extra references per node. Since you're building what is in effect two skip lists in one, expect your nodes to require, on average, four extra references per node.
Edit after comment
If, as you say, you don't control List, then you still maintain this dual skip list that I described. But the data stored in the skip list is just the index into List. You said that List is observable, so you get notification of all insert and delete operations, so you should be able to maintain an index by reacting to all notifications.
When somebody wants to operate on FilteredList, you use the filtered index links to find the List index of the FilteredList record the user wanted to affect. Then you pass the request onto List, using the translated index. And then you react to the observable notification from List.
Basically, you're just maintaining a secondary index into List, so that you can translate FilteredList indexes into List indexes.

Find isolated groups of blocks in a grid

I have a grid of "blocks" (in the form of a 2D array, could be 5*5, 17*17 or whatever) where I can add or remove blocks at will, except for the one at the center that should always remain there.
I can place blocks if they have a local neighbour : on their right/left/up/down (at least one of them).
By removing some blocks, it may leave other blocks isolated with no "connection" to the center-block, and I want to avoid this.
I'm looking for a quick solution to check if all my blocks have a connection to the center, the simplest possible (in terms of coding, I can accept to have a non optimal solution since this is supposed to be on executed on very small data and not so often). The first thing that came to my mind was to implement this as a path search but that seems overkill.
I'm using C++ but that should not make any difference.
You need to find the connected components using DFS/BFS.Construct the initial graph and as you add new blocks, you can add new edges, or when you remove blocks you can remove edges.When you remove a block, temporarily delete those edges in the graph and check if it causes two pieces of the graph to disconnect.This is simple, carry out DFS again.If it does not disconnect you can remove that block.
DFS is only about 8 lines to implement, and for small data sets this is elegant.

Efficient mass modification of persistent data structures

I understand how typically trees are used to modify persistent data structures (create a new node and replace all it's ancestors).
But what if I have a tree of 10,000's of nodes and I need to modify 1000's of them? I don't want to go through and create 1000's of new roots, I only need the one new root that results from modifying everything at once.
For example:
Let's take a persistent binary tree for example. In the single update node case, it does a search until it finds the node, creates a new one with the modifications and the old children, and creates new ancestors up to the root.
In the bulk update case could we do:
Instead of just updating a single node, you're going to update 1000 nodes on it in one pass.
At the root node, the current list is the full list. You then split that list between those that match the left node and those that match the right. If none match one of the children, don't descend to it. You then descend to the left node (assuming there were matches), split its search list between its children, and continue. When you have a single node and a match, you update it and go back up, replacing and updating ancestors and other branches as appropriate.
This would result in only one new root even though it modified any number of nodes.
These kind of "mass modification" operations are sometimes called bulk updates. Of course, the details will vary depending on exactly what kind of data structure you are working with and what kind of modifications you are trying to perform.
Typical kinds of operations might include "delete all values satisfying some condition" or "increment the values associated with all the keys in this list". Frequently, these operations can be performed in a single walk over the entire structure, taking O(n) time.
You seem to be concerned about the memory allocation involved in creating "1000's of new roots". Typical allocation for performing the operations one at a time would be O(k log n), where k is the number of nodes being modified. Typical allocation for performing the single walk over the entire structure would be O(n). Which is better depends on k and n.
In some cases, you can decrease the amount of allocation--at the cost of more complicated code--by paying special attention to when changes occur. For example, if you have a recursive algorithm that returns a tree, you might modify the algorithm to return a tree together with a boolean indicating whether anything has changed. The algorithm could then check those booleans before allocating a new node to see whether the old node can safely be reused. However, people don't usually bother with this extra check unless and until they have evidence that the extra memory allocation is actually a problem.
A particular implementation of what you're looking for can be found in Clojure's (and ClojureScript's) transients.
In short, given a fully-immutable, persistent data structure, a transient version of it will make changes using destructive (allocation-efficient) mutation, which you can flip back into a proper persistent data structure again when you're done with your performance-sensitive operations. It is only at the transition back to a persistent data structure that new roots are created (for example), thus amortizing the attendant cost over the number of logical operations you performed on the structure while it was in its transient form.

Lock Free Deque that supports removing an arbitrary node

This needs to be lock free as it has to run in the interrupt handler of an SMP system. I cannot take locks.
I have a contiguous array holding some values. Some of the entries in this array are "free", they are not occupied. I want to make a list of these entries so that I can quickly allocate one. However, I occasionally have to allocate an arbitrary entry.
Therefore, I see the following would be a nice way of doing things:
The contiguous array holds not just values but also left and right pointers, thus making a deque. Only free values have valid left/right pointers. I can quickly get to arbitrary nodes because it is just an index access into the deque.
Now, to the crux of it: Is there a nice lock free deque algorithm that is relatively efficient and can support the removal of an arbitrary node?
The contiguous array holds not just values but also left and right pointers, thus making
a deque.
[snip]
Now, to the crux of it: Is there a nice lock free deque algorithm that is relatively
efficient and can support the removal of an arbitrary node?
A deque with the ability to remove arbitrary elements is really a doubly linked list; the only thing you've given up is the ability to insert arbitrary elements and removing is the hard part - if you can remove, you can certainly add.
A lock-free doubly linked list exists, but it requires garbage collection.
How about this; have a freelist. This represents available nodes. The nodes are actually an array, so you can index into them. When you have to use an arbitrary node, index into the array and then CAS a flag in that element but leave it in the freelist (you have to of course, since it's not at the top of the freelist). When you come in future to pop and you find you pop an element which has already been used, just keep popping till you find one which is free.
In a garbage-collected system, it's possible to have a singly linked list support lock-free logical removal of items, if you don't care about when the memory for the items physically gets freed, and if it's not possible to add an item immediately following an item that's being deleted. Give each item a deleted flag, and have a list-traversal routine that will check as it visits each item whether the following node has been deleted; if it has, use compare and swap to swing the present node's "next" pointer around it. Note that it's possible that the "next" pointer of the node which was being deleted might get changed, but only to skip the node following it. It's possible that swinging a next pointer might cause a node which has just been unlinked from the list to get relinked (e.g. A->B->C->D might, if B and C are removed simultaneously, become A->B->D (swinging B
s pointer) and then A->C->D (swinging A's pointer to the latched value of B's 'next' pointer). If node C was and continues to be flagged as "deleted", however, that shouldn't pose a problem, since the next time the list is iterated, A's pointer will swing to D.
Two caveats: -1- In a non-garbage-collected system, it may be difficult to know when a node can really be freed; freeing a node and then swinging a pointer back to it could cause Undefined Behavior; -2- If a node is added immediately following a deleted node, a pointer may swing so as to disconnect the new node. If nodes will always be added to the end of the queue, one can avoid this latter problem by ending the queue with a dummy node, which cannot be deleted until there's another node following it.

Resources