-
Notifications
You must be signed in to change notification settings - Fork 825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Boyer-Myrvold planarity testing algorithm #795
Conversation
Regarding the list implementation, I suggest moving it to org.jgrapht.util, and name it DoublyLinkedList. As a followup pull request after this one gets merged, use it to replace other instances where something similar appears (WarnsdorffRuleKnightTourHeuristic, and your BlossomV if applicable). Regarding the Kuratowski subdivision checking methods, yes, they can go in GraphTests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job! Some minor comments about typos and function names.
|
||
/** | ||
* Computes combinatorial embedding of the input {@code graph}. This method will return | ||
* a valid result only if the {@code graph} is planar. For more information on the combinarotial |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo
|
||
/** | ||
* Uses BFS to find all vertices of the {@code graph} which have a degree {@code degree}. | ||
* This method doesn't advance to new nodes after the it finds a node with a degree {@code degree} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo
* @param <E> the list element type | ||
* @author Timofey Chudakov | ||
*/ | ||
public class ElementList<E> implements Iterable<E> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are going to keep this, I suggest to add a modCount
just like LinkedList
and throw a ConcurrentModificationException
when detected.
* | ||
* @return the number of elements in this list | ||
*/ | ||
public int getSize() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to use similar names like the List
interface.
* | ||
* @param list the list to prepend | ||
*/ | ||
public void prepend(ElementList<E> list) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to use similar names like the ArrayDeque
. This would make it easier for other Java users. For example "prepend" -> "addFirst" and "append" -> "addLast". Same comment applies in other names also.
* @param element the element of this list to search the list node of. | ||
* @return the list node allocate for the {@code element}, or {@code null} if this list doesn't contain | ||
* the {@code element} | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mention complexity of this method and the fact that equality checks uses method equals()
.
/** | ||
* Performs sorting of the vertices by their lowpoints and adding them to the {@code separatedDfsChildList} lists | ||
*/ | ||
private void sortVetices() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo
} | ||
} | ||
} | ||
// for (Node node : nodes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented code.
I haven't renamed the methods @jsichi that's a good idea. I think using the |
(@Toptachamann we could also have an IntrusiveDoublyLinkedList to avoid the memory increase, like boost https://www.boost.org/doc/libs/1_64_0/doc/html/intrusive/list.html) |
@Toptachamann what's the status of this PR? |
The current issue is that I need to understand the idea about intrusive lists. So, we need to implement something like class IntrusiveListHook {
IntrusiveListHook prev, next;
public IntrusiveListHook next(){...}
public IntrusiveListHook prev(){...}
...
} and then we might have class Node extends IntrusiveListHook {
...
} @jsichi Indeed, this is a good idea to try. The thing that I don't currently understand is how this can be used when we need to store the same node in multiple lists? |
Hmm, I forgot about the fact that C++ can deal with multiple inheritance instantiation of the same base class, whereas Java can't. (Likewise, the Boost member technique relies on being able to calculate the memory offset from the beginning of the object to the member, which isn't applicable to Java.) So there may be no easy+clean way to do it. In any case, this PR itself should not be held up for intrusive lists; my suggestion was to address that in a followup PR. |
No further comments from me. This looks ready to be merged! |
I'll go ahead and merge this in a few days unless I see new comments from @jkinable Finally we can update our "open tasks" page! |
I'm at a conference till Wednesday, I made a note to look at this on
Thursday
…On Tue, Oct 15, 2019, 11:13 AM John Sichi ***@***.***> wrote:
I'll go ahead and merge this in a few days unless I see new comments from
@jkinable <https://github.com/jkinable>
Finally we can update our "open tasks" page!
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#795?email_source=notifications&email_token=AAU5RSV652VOSKSS6V35TJ3QOYB5XA5CNFSM4HYRF2QKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBJW6WY#issuecomment-542338907>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAU5RSQNKJXD4XGE4DRDSBLQOYB5XANCNFSM4HYRF2QA>
.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beautiful, absolutely well done @Toptachamann ! I'm super happy that we can finally take this of our wish list.
* @param <E> the list element type | ||
* @author Timofey Chudakov | ||
*/ | ||
public class DoublyLinkedList<E> implements Iterable<E> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a future PR, it might be good to see whether we can also implement the List
interface.
jgrapht-core/src/main/java/org/jgrapht/util/DoublyLinkedList.java
Outdated
Show resolved
Hide resolved
/** | ||
* Returns a reverse iterator over this list, which starts from the {@code element}. | ||
* Note: the returned iterator will iterate over the all list, meaning it won't | ||
* stop at the end of the list unless the {@code element} is the beginning of the list. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this. If an element is the first element of the list, why wouldn't the reverseIterator wrap around and walk the list back to the beginning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, this is a bit incorrect. The reverse iterator will stop at the beginning of the list in the case the start node is the last element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still find the description of reverseIteratorFrom(.)
confusing. What about the following description:
Returns an iterator over this list, which traverses the list in the reverse direction. The returned iterator will iterate over the <i>entire</i> list, that is, the list is treated as if it were cyclic. The iterator starts from {@code element}, and walks the list backwards, while wrapping around at the beginning of the list. For instance, for the list [1,2,3,4], {@code reverseIteratorFrom(3)} would return 3,2,1,4.
This method throws {@link NoSuchElementException} in the case {@code element} doesn't belong to this list. This method invokes {@link #getNode(Object) getNode} to find the list node containing {@code element}.
} | ||
|
||
/** | ||
* Checks whether the {@code graph} is a $K_5$ subdivision. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
High level comment:
|
||
/** | ||
* Finds and returns the list node allocate for the {@code element}. If this list doesn't contain | ||
* the {@code element}, returns {@code null}. The timer complexity of this method is linear in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: timer->time
Awesome work @Toptachamann ! We can finally remove this from our todo list. Keep up the good work :) |
Finally, implemented a linear time planarity testing and embedding algorithm with Kuratowski subdivision extraction option #730. The implemented algorithm is an iterative version of the Boyer-Myrvold algorithm. The implementation is tested on a large number of graph instances (10^5 triangulations and 10^5 random graphs). Here is a running time comparison with the left-right planarity testing algorithm:
From the plot above it is clear that the Boyer-Myrvold algorithm is slightly faster than the left-right algorithm, but it has a more complicated logic. In the case of the left-right algorithm, the testing phase consists of 2 dfs traversals, embedding phase consists of 1 more dfs traversal. The dfs traversals in the left-right algorithm were also made iterative.
A couple of questions:
planar
package. Should I move somewhere?PlanarityTestingAlgorithm
has 3 methods for testing whether a graph is a Kuratowski subdivision. Should I move these methods to theGraphTests
class?HISTORY.md
orCONTRIBUTORS.md