Skip to content
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

Use Ozaki et al.'s error bound and single-branch evaluation in orientation index filter. #1184

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tinko92
Copy link
Contributor

@tinko92 tinko92 commented Oct 27, 2024

This PR is separated out of #1162 . It contains two changes to the orientation predicate.

The first change changes the relative error bound from currently 1e-15 to ~3.33e-16, which is proven to be sufficient in https://doi.org/10.1007/s10543-015-0574-9 by Ozaki et al. A tighter error bound can reduce the calls to the expensive exact computation in some degenerate cases (Edit: Here is a gist demonstrating this for a sequence of 100k generated near-collinear inputs https://gist.github.com/tinko92/ce44f93d8d4e4d5909310c00cf19b391 ) and has no disadvantages.

The second changes is also motivated by https://doi.org/10.1007/s10543-015-0574-9 and reduces the number of branches and instructions in the evaluation. This is more concise and may result in faster evaluation (benchmarks are in the referenced paper) but I am not currently aware of any geos-benchmarks, beside the Orientation Index micro benchmark, for which the orientation predicate is the bottle neck. The original logic that is replaced is from the function body of REAL orient2d(pa, pb, pc) https://www.cs.cmu.edu/afs/cs/project/quake/public/code/predicates.c , where the early returns make use of the branching in the fabs-computation, discussed in the comment preceding #define Absolute(a) ((a) >= 0.0 ? (a) : -(a)). This reasoning is obsolete because modern compilers with enabled optimizations will compile fabs to a branchless masking of the sign bit.

Edit: I did not remove the orientation(double x) function, which seems unused now, because I don't know if that would be considered an API change (it's not in a namespace called detail or internal or sth. like that and I don't know the geos conventions). But I can edit the commit if it is no longer needed.

Edit2: Sorry for only now reading more about the jts-geos-relationship/-process. I will propose the same change to JTS, when I find time. Having said that, since patched and unpatched always return the correct orientation by deferring filter misses to the exact computation for inputs that do not go near overflow/underflow, this would not change observable behavior between JTS/Geos for the same inputs, except in computation time, so I think it classifies as an implementation detail/optimization.

@dr-jts
Copy link
Contributor

dr-jts commented Oct 28, 2024

Edit2: Sorry for only now reading more about the jts-geos-relationship/-process. I will propose the same change to JTS, when I find time. Having said that, since patched and unpatched always return the correct orientation by deferring filter misses to the exact computation for inputs that do not go near overflow/underflow, this would not change observable behavior between JTS/Geos for the same inputs, except in computation time, so I think it classifies as an implementation detail/optimization.

Thanks for providing a PR for JTS well. It's correct that the two libraries sometimes diverge in implementation, but it's nice to keep them in synch as far as possible, to reduce the mental complexity of future debugging.

@tinko92 tinko92 force-pushed the orientation-tighter-error-bound branch from 57586ed to 8e4e03e Compare October 28, 2024 22:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or feature improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants