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

Fix #179 #178

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

Fix #179 #178

wants to merge 8 commits into from

Conversation

janbridley
Copy link
Collaborator

@janbridley janbridley commented Feb 13, 2023

Description

minimal_bounding_sphere will fail for a number of augmented Johnson solids, due to numerical imprecision inherent to the miniball package. Switching to the faster, more robust cyminiball solver (see #179, here) will improve the calculated results and implementing an internal check will ensure calculated results are accurate to an arbitrarily high degree of precision - in this case, 1e-15 or approximately 10*machine epsilon.

Possible discussion

Current worst case runtime observed over 15000 tests on an m1 Mac is 0.3 seconds, with an average runtime of 0.006s and a 1% high of 0.1s. Reducing precision can accelerate the worst case, but does not significantly change the 1% highs. Note that in every case, the miniball for augmented Johnson solids takes far longer than simple polyhedra so most users (those who primarily test Platonic, Archimedean, and Catalan solids) will not be negatively impacted by this change. This behavior is expected, as instability in the miniball solver increases with increasing degree of asphericity.

Types of Changes

  • Documentation update
  • Bug fix
  • New feature

Checklist:

Only test quaternions that are not effectively zero.
@janbridley janbridley self-assigned this Feb 13, 2023
@codecov
Copy link

codecov bot commented Feb 13, 2023

Codecov Report

Attention: 5 lines in your changes are missing coverage. Please review.

Comparison is base (926e41c) 54.88% compared to head (a69457c) 54.31%.
Report is 17 commits behind head on master.

❗ Current head a69457c differs from pull request most recent head f027272. Consider uploading reports for the commit f027272 to get more accurate results

Files Patch % Lines
coxeter/shapes/polyhedron.py 55.55% 4 Missing ⚠️
coxeter/shapes/polygon.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #178      +/-   ##
==========================================
- Coverage   54.88%   54.31%   -0.57%     
==========================================
  Files          24       27       +3     
  Lines        2551     2629      +78     
==========================================
+ Hits         1400     1428      +28     
- Misses       1151     1201      +50     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@janbridley janbridley force-pushed the fix-minimal_bounding_sphere branch from 2863227 to f0b8598 Compare February 21, 2023 01:03
@janbridley janbridley changed the title Fix minimal bounding sphere Fix #179 Feb 21, 2023
Replacing the ``miniball`` package with the improved ``cyminiball`` c++ binding allows for accurate calculation of a minimal_bounding_sphere for complex polyhedra. An internal test to ensure vertices are within (or extremely close to) the minimal bounding sphere confirms expected behavior and catches cases where an incorrect miniball could be calculated.
@janbridley janbridley marked this pull request as ready for review February 21, 2023 02:05
@janbridley janbridley requested a review from a team February 21, 2023 02:05
Copy link
Member

@bdice bdice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. The issue and PR descriptions were very helpful. I have some comments to discuss.

coxeter/shapes/polyhedron.py Outdated Show resolved Hide resolved
coxeter/shapes/polyhedron.py Outdated Show resolved Hide resolved
# The following subfunction checks if all vertices lie within the
# minimal bounding sphere, to a tolerance of 1e-15.
def verify_inside(points, center, radius, eps=1e-15):
return np.all(np.linalg.norm(points - center, axis=1) <= radius + eps)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we compare squared distances? If we avoid the square root in the norm here and just use sum-of-squares, we can also reuse the value of r2 below without incurring another sqrt. Just depends on whether you think the epsilon is more meaningful in terms of distance rather than distance squared, I suppose.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For small distances (e.g. for points that are very close to the bounding sphere), ε will be more significant and therefore represent a larger tolerance range for accepted points. This is magnified for square distances, so if we do make this change we should probably test a smaller ε. I will set this aside while I figure out hbf/miniball and we can revisit later

break
except np.linalg.LinAlgError:
current_rotation = rowan.random.rand(1)
vertices = rowan.rotate(current_rotation, vertices)
except AssertionError:
Copy link
Member

@bdice bdice Feb 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s combine this with the previous LinAlgError and handle both at the same time, since the subsequent code paths are identical. Should look something like:

Suggested change
except AssertionError:
except (np.linalg.LinAlgError, AssertionError):

@bdice
Copy link
Member

bdice commented Feb 21, 2023

@janbridley FYI, I merged in the upstream to fix CI failures.

Copy link
Member

@joaander joaander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cyminibal is GPL licensed. See details in #179.

janbridley added a commit that referenced this pull request Feb 27, 2023
This reverts commit 40f500c, moving all miniball-related changes to #178.
Tobias-Dwyer pushed a commit that referenced this pull request Mar 27, 2023
… solids. (#177)

* test: Fix assumption on quaternions.

Only test quaternions that are not effectively zero.

* Added new classes to return the edges of polyhedra

The new class ``polyhedron.edges`` returns the a list of the edges of a polyhedron as vertex-index pairs, similar to the current ``polyhedron.faces`` class. The class ``polyhedron.get_edge_vectors`` returns a list of edges as vectors in 3D space.

* Added json files for new shape families as well as accompanying import functions.

* Added new pytest marks and a few test functions.

* New pytest marks have been created for the Archimedean, Catalan, and Johnson shape families.
* A function has been written to combine multiple marks into a single mark for more compact testing of shape properties.
* test_volume function for damasceno shapes has been adapted to test the new shape families
* A test_surface_area method similar to test_volume has been added.

* Tightnened tolerance for test_insphere and increased deadline

Tightened ``atol`` of ``test_insphere``. Increased the deadline of the test to accommodate testing of shapes with many faces (e.g. disdyakis triacontahedron).

* Applied test_bounding_sphere to archimedean solids

* Tightened tolerance for test_bounding_sphere

* Added marks for prism/antiprism and pyramid/dipyramid families

* Applied test_get_set_minimal_centered_bounding_sphere_radius to all new shape families, including prism/antiprism and pyramid/dipyramid

* Applied test_volume and test_surface_area to prism/antiprism and pyramid/dipyramid. Fixed typo in conftest

* Formatted code with black.

* Revert commit "Added new classes to return the edges of polyhedra"

This commit reverts changes made in  ab21279, which are included in a different PR.

* Fixed docstring for common.py

* Split test_insphere into multiple functions based on input data complexity.

The Random3DRotationStrategy test varies widely in runtime based on the complexity of the input shape. Splitting the calling function into two tests (for simple Platonic shapes and more complex Catalan shapes) should solve this issue.

* Increased resilience of minimal_bounding_sphere method

The ``minimal_bounding_sphere`` method is reliant on the solution to a linear system of equations. For polyhedra with portions that protrude out from the main mass, this method can fail due to numerical instability in a small percent of cases. This fix double-checks that the calculated miniball contains all points on the polyhedron, and allows the method to make more attempts to find a correct answer before failing.

* Revert "Increased resilience of minimal_bounding_sphere method"

This reverts commit 40f500c, moving all miniball-related changes to #178.

* Removed unnecessary print statement in the combine_mark function

* Updated Credits.rst to not conflict with master

* Fixed missing space in archimedean.json "Truncated Cuboctahedron"

* Added additional pytest for json data and new families

---------

Co-authored-by: Brandon Butler <[email protected]>
Co-authored-by: Vyas Ramasubramani <[email protected]>
@janbridley janbridley mentioned this pull request Feb 20, 2024
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants