polliwog icon indicating copy to clipboard operation
polliwog copied to clipboard

Fix point-on-plane detection for NumPy 1.19.0 in Linux

Open paulmelnikow opened this issue 4 years ago • 5 comments

This fixes the tests that are failing in NumPy 1.19.0.

See https://app.circleci.com/pipelines/github/lace/polliwog/836/workflows/b88ac698-51bc-46ea-80b8-f9e57e7157d9/jobs/2618/steps

_________ test_open_starts_in_front_ends_in_back_with_vertex_on_plane __________

    def test_open_starts_in_front_ends_in_back_with_vertex_on_plane():
        signs = np.array([1, 1, 1, 0, -1, -1, -1, -1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:62: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([ 1,  1,  1,  0, -1, -1, -1, -1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 8 (12.5%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([ 1.,  1.,  1.,  1., -1., -1., -1., -1.])
E        y: array([ 1,  1,  1,  0, -1, -1, -1, -1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
_________ test_open_starts_in_back_ends_in_front_with_vertex_on_plane __________

    def test_open_starts_in_back_ends_in_front_with_vertex_on_plane():
        signs = np.array([-1, -1, -1, -1, -1, 0, 1, 1, 1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:88: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([-1, -1, -1, -1, -1,  0,  1,  1,  1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 9 (11.1%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([-1., -1., -1., -1., -1.,  1.,  1.,  1.,  1.])
E        y: array([-1, -1, -1, -1, -1,  0,  1,  1,  1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
___________________ test_open_starts_on_plane_ends_in_front ____________________

    def test_open_starts_on_plane_ends_in_front():
        signs = np.array([0, 1, 1, 1, 1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:97: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([0, 1, 1, 1, 1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 5 (20%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([1., 1., 1., 1., 1.])
E        y: array([0, 1, 1, 1, 1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
____________ test_open_starts_with_edges_along_plane_ends_in_front _____________

    def test_open_starts_with_edges_along_plane_ends_in_front():
        signs = np.array([0, 0, 1, 1, 1, 1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:106: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([0, 0, 1, 1, 1, 1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 2 / 6 (33.3%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([1., 1., 1., 1., 1., 1.])
E        y: array([0, 0, 1, 1, 1, 1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
____________________ test_open_starts_on_plane_ends_in_back ____________________

    def test_open_starts_on_plane_ends_in_back():
        signs = np.array([0, -1, -1, -1, -1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:115: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([ 0, -1, -1, -1, -1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 5 (20%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([ 1., -1., -1., -1., -1.])
E        y: array([ 0, -1, -1, -1, -1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
___________________ test_open_starts_in_front_ends_on_plane ____________________

    def test_open_starts_in_front_ends_on_plane():
        signs = np.array([1, 1, 1, 1, 0])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:125: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([1, 1, 1, 1, 0])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 5 (20%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([1., 1., 1., 1., 1.])
E        y: array([1, 1, 1, 1, 0])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
____________ test_open_starts_in_front_ends_with_edges_along_plane _____________

    def test_open_starts_in_front_ends_with_edges_along_plane():
        signs = np.array([1, 1, 1, 1, 0, 0])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:134: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([1, 1, 1, 1, 0, 0])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 2 / 6 (33.3%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([1., 1., 1., 1., 1., 1.])
E        y: array([1, 1, 1, 1, 0, 0])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
_____________________ test_open_in_back_then_ends_on_plane _____________________

    def test_open_in_back_then_ends_on_plane():
        signs = np.array([-1, -1, -1, -1, 0])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:143: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([-1, -1, -1, -1,  0])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 5 (20%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([-1., -1., -1., -1.,  1.])
E        y: array([-1, -1, -1, -1,  0])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
________ test_open_starts_in_front_then_along_plane_then_in_front_again ________

    def test_open_starts_in_front_then_along_plane_then_in_front_again():
        signs = np.array([1, 1, 0, 0, 1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:153: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([1, 1, 0, 0, 1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 2 / 5 (40%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([1., 1., 1., 1., 1.])
E        y: array([1, 1, 0, 0, 1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
__ test_open_starts_in_back_then_along_plane_then_in_front_then_in_back_again __

    def test_open_starts_in_back_then_along_plane_then_in_front_then_in_back_again():
        signs = np.array([-1, -1, 0, 0, 1, 1, 1, -1, -1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:181: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([-1, -1,  0,  0,  1,  1,  1, -1, -1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 2 / 9 (22.2%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([-1., -1.,  1.,  1.,  1.,  1.,  1., -1., -1.])
E        y: array([-1, -1,  0,  0,  1,  1,  1, -1, -1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
___________ test_open_starts_in_front_then_along_plane_then_in_back ____________

    def test_open_starts_in_front_then_along_plane_then_in_back():
        signs = np.array([1, 1, 0, 0, -1])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([ 1,  1,  0,  0, -1])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 2 / 5 (40%)
E       Max absolute difference: 1.
E       Max relative difference: 0.
E        x: array([ 1.,  1.,  1.,  1., -1.])
E        y: array([ 1,  1,  0,  0, -1])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
____________________________ test_open_all_in_plane ____________________________

    def test_open_all_in_plane():
        signs = np.array([0, 0])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:228: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([0, 0])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 2 / 2 (100%)
E       Max absolute difference: 1.
E       Max relative difference: inf
E        x: array([1., 1.])
E        y: array([0, 0])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError
_________________________ test_open_one_vert_on_plane __________________________

    def test_open_one_vert_on_plane():
        signs = np.array([0])
>       vertices = vertices_with_signs(signs)

polliwog/polyline/test_slice_by_plane.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signs = array([0])

    def vertices_with_signs(signs):
        num_verts = len(signs)
        random_points_on_plane = plane.project_point(rand_nonzero(num_verts, 3))
        random_displacement_along_normal = (
            rand_nonzero(num_verts).reshape(-1, 1) * plane_normal
        )
        vertices = (
            random_points_on_plane + signs.reshape(-1, 1) * random_displacement_along_normal
        )
        # Because of rounding, the random points don't necessarily return 0 for
        # sign, so pick one that does.
        vertices[signs == 0] = plane.reference_point
>       np.testing.assert_array_equal(plane.sign(vertices), signs)
E       AssertionError: 
E       Arrays are not equal
E       
E       Mismatched elements: 1 / 1 (100%)
E       Max absolute difference: 1.
E       Max relative difference: inf
E        x: array([1.])
E        y: array([0])

polliwog/polyline/test_slice_by_plane.py:28: AssertionError

Closes #198

paulmelnikow avatar Jul 03 '20 20:07 paulmelnikow

@paulmelnikow Can you confirm that the idea behind this PR is to work around small numerical precision differences in Numpy 1.19 between your local OS X development machine, and the remote Linux CI server?

jbeard4 avatar Jul 30 '20 00:07 jbeard4

I forget whether or not it's reproducible on OS X. Though yes, the way I'd put it is that the goal is to make the code work the same in NumPy 1.19 on Linux as it did in earlier versions of NumPy on Linux.

These tests started failing when NumPy 1.19 was released and I had to pin the NumPy version back to 1.18 to get them working again.

I can re-check OS X tomorrow if it's helpful.

paulmelnikow avatar Jul 30 '20 00:07 paulmelnikow

I am fine with this fix, but I wonder if it would be better to regard it as a workaround to a regression in numpy. Do you think this is an issue that should get reported upstream?

jbeard4 avatar Jul 30 '20 02:07 jbeard4

I am fine with this fix, but I wonder if it would be better to regard it as a workaround to a regression in numpy. Do you think this is an issue that should get reported upstream?

I do not know for sure whether or not this is a regression. It's possible. Though in general, I do not expect floating point multiplication and division to produce values which exactly equal zero. However that's what NumPy used to do until 1.19.

It's not the first time a NumPy upgrade has caused unexpected regressions in downstream code. I do know that NumPy 1.19 dropped Python 2 and a bunch of legacy code along the way.

Would you like to try to isolate the issue and report it?

I do think if this is a temporary workaround for a regression we should mark it up in the codebase with TODO comments.

paulmelnikow avatar Jul 30 '20 17:07 paulmelnikow

Let's confirm with upstream numpy that this is the expected behavior going forward, then merge this PR into our codebase.

jbeard4 avatar Oct 25 '20 23:10 jbeard4