-
Notifications
You must be signed in to change notification settings - Fork 212
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
"is_straight_line_drawing()" is buggy for large graphs #388
Comments
I suggest the minimized version Live On Coliru #include <boost/graph/adjacency_list.hpp>
#include <boost/graph/is_straight_line_drawing.hpp>
int main() {
boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> g;
add_edge(0, 1, g);
add_edge(2, 0, g);
add_edge(1, 2, g);
struct coord_t { size_t x, y; };
std::vector<coord_t> coordinates{{4143438, 86426}, {4064945, 7932}, {4064944, 7931}};
assert(is_straight_line_drawing(g, coordinates.data())); // FAILS
} After all, you're not depending on the algorithms, you're just hardcoding three points taken from a larger output. |
It's unclear to me how you want to achieve that. The acceptable tolerance is subjective/context dependent at best. In any solution I can imagine, one would still have to use some given tolerance. I'd suggest that you want to be able to specify the precision of the calculation type and tolerance of the comparison. |
At the very least the doc and code don't match, the doc says that |
Very simple, eg. with first Wikipedia link algorithm I provided:
So while the formula shows a faction, the nominator and denominator are integers because the the straight line drawing coordinates are (convertible to) std::size_t. A test whether t and u are in [0..1] can be done without division, just with integer comparison in integer coordinate case, for denom>0 [for graph edge intersection test (0..1) needs to tested, with > and < instead]:
The O(n*log(n)) "sweep" part of the algorithm defines then x- and y-coord types as std::size_t:
So
should be changed to
without epsilon, and implemented with any of the integer coordinate precision loss free algorithms. |
Multiprecision would be overkill and slower than std::size_t. While I tested straight line drawing algorithm for up to 10 million vertices for now, I plan to test much higher as well when switching on (slower) Xeon server with 384GB RAM (10 million vertices did just fit into the 32GB RAM my 7950X PC has). But even with that restriction of new function to graphs with at most 2 billion vertices would be OK for me. |
Systems with 32-bit size_t still exist, using size_t instead of double for those may be a regression. On the other hand, in C++11, they must provide at least one 64-bit type (
Nothing says |
Agreed, a 64bit type for 32bit systems. |
Unless you document and assert that the input must fit in 30 bits or so.
If adding a dependency on Boost.Multiprecision is ok, I'd suggest (by the way, I am not a maintainer, just giving random advice) |
If it's a geometry calculation, I'm inclined to just use Boost.Geometry and let them decide on the best way to calculate it. |
Btw, best way to get this solved is to first open a PR that adds a failing test. Once we agree that the test is correct (meaning, it should pass), then someone (maybe you, maybe me, maybe someone else) use it to trial solutions. In this case, the more numerical edge cases the better, but even one is enough to get started. |
There was an existing testcase, so I named the new testcase "...issue.cpp":
Since it fails it should not be part of Jamfile.v2 for now:
My graph fork is blocked by outstanding PR 387.
P.S: P.P.S: "[Boost] runtime+memory evaluation of 6 BGL planar graph algorithms" |
I don't really have time to create and work on PRs, sorry. I can help you with your PRs, and I think this bug is orthogonal to #387, so you can just go ahead and create a new PR specifically for it. I suggest you do put the test in the Jamfile -- you essentially want a red/failing PR, because that in some sense proves that the new test is novel. |
yes.
I created new "bug_is_straight_line_drawing" branch in my fork. |
Ok, sounds like you're not too familiar with git? It's a very powerful and flexible tool, so I suggest reading the manual over time: What you needed to do was to create your new branch starting not from your existing feature branch, but starting from |
@sehe do you have time? |
Actually, this is probably a pretty small task, I'll try to find time to do it. |
I played with Boost.Geometry and wanted to use intersection(). First I tried intersection of two linestrings, but that is not implemented:
So I used polygon with only "outer", no "inner".
Intersection should be point "1 1", here is g4.cpp:
|
You may want to ask the Boost.Geometry people. They have their own mailing list, although it seems a bit dead. They have also enabled github discussions. |
I learned how to create a branch for providing new testcase. |
✅
Correct.
I created new discussion: |
Oops, the last and only 2023 posting from mailing list has probably the solution: |
"crosses" fits the requirement as it means that the interior parts of the geometry share some common points, not exterior parts such as end-points, and it means "not within".
I experienced "is_straight_line_drawing()" returning false for valid straight line drawing of a maximal planar graph with 10million vertices first:
https://lists.boost.org/Archives/boost/2024/10/257979.php
Later I was able to reduce to 1million vertices, and now to only three vertices with this simplified gist:
https://gist.github.com/Hermann-SW/992b43eef29f1ef28c4bf2727f0a7c16
After the straight line drawing for the K₃ was computed, I did overwrite the determined coordinates for the three vertices with the coordinates of three vertices reported for initial 10million vertex graph. With that coordinates and the edges in same direction as in previous graph the problem is recreated fast:
The problem is that "is_straight_line_drawing()" working on coordinates of std::size_t does call function using double, causing false report:
There are plenty of intersection test algorithms that avoid doing division and report correct result for integer coordinates, eg:
"bool intersects()" needs to be implemented with integer coordinates for correct response.
This is the graph from recreate gist:
And these are the coordinates:
There is a very small angle between edge 0--1 and edge 2--0 at vertex 0, with slope of edges 78494/78493 and 78495/78494, which cannot be correctly handled by double type function:
The text was updated successfully, but these errors were encountered: