wolph / numpy-stl

Simple library to make working with STL files (and 3D objects in general) fast and easy.
http://numpy-stl.readthedocs.org/
BSD 3-Clause "New" or "Revised" License
624 stars 105 forks source link

2.4.1: test_rotation fails on ppc64le #78

Closed hroncok closed 6 years ago

hroncok commented 6 years ago

I'm not familiar with ppc64le that much, but apparently something is broken here:

=================================== FAILURES ===================================
_____________________________ test_rotation[False] _____________________________
    def test_rotation():
        # Create 6 faces of a cube
        data = numpy.zeros(6, dtype=Mesh.dtype)

        # Top of the cube
        data['vectors'][0] = numpy.array([[0, 1, 1],
                                          [1, 0, 1],
                                          [0, 0, 1]])
        data['vectors'][1] = numpy.array([[1, 0, 1],
                                          [0, 1, 1],
                                          [1, 1, 1]])
        # Right face
        data['vectors'][2] = numpy.array([[1, 0, 0],
                                          [1, 0, 1],
                                          [1, 1, 0]])
        data['vectors'][3] = numpy.array([[1, 1, 1],
                                          [1, 0, 1],
                                          [1, 1, 0]])
        # Left face
        data['vectors'][4] = numpy.array([[0, 0, 0],
                                          [1, 0, 0],
                                          [1, 0, 1]])
        data['vectors'][5] = numpy.array([[0, 0, 0],
                                          [0, 0, 1],
                                          [1, 0, 1]])

        mesh = Mesh(data, remove_empty_areas=False)

        # Since the cube faces are from 0 to 1 we can move it to the middle by
        # substracting .5
        data['vectors'] -= .5

        # Rotate 90 degrees over the X axis followed by the Y axis followed by the
        # X axis
        mesh.rotate([0.5, 0.0, 0.0], math.radians(90))
        mesh.rotate([0.0, 0.5, 0.0], math.radians(90))
        mesh.rotate([0.5, 0.0, 0.0], math.radians(90))

        # Since the cube faces are from 0 to 1 we can move it to the middle by
        # substracting .5
        data['vectors'] += .5

>       assert (mesh.vectors == numpy.array([
            [[1, 0, 0], [0, 1, 0], [0, 0, 0]],
            [[0, 1, 0], [1, 0, 0], [1, 1, 0]],
            [[0, 1, 1], [0, 1, 0], [1, 1, 1]],
            [[1, 1, 0], [0, 1, 0], [1, 1, 1]],
            [[0, 0, 1], [0, 1, 1], [0, 1, 0]],
            [[0, 0, 1], [0, 0, 0], [0, 1, 0]],
        ])).all()
E       AssertionError: assert False
E        +  where False = <built-in method all of numpy.ndarray object at 0x7fff889a3710>()
E        +    where <built-in method all of numpy.ndarray object at 0x7fff889a3710> = array([[[9.99...dtype=float32) == array([[[1, 0,...  [0, 1, 0]]])
E             Full diff:
E             - array([[[9.9999994e-01, 2.9802322e-08, 0.0000000e+00],
E             -         [2.9802322e-08, 1.0000000e+00, 5.9604645e-08],
E             -         [0.0000000e+00, 5.9604645e-08, 2.9802322e-08]],
E             + array([[[1, 0, 0],
E             +         [0, 1, 0],
E             +         [0, 0, 0]],...
E             
E             ...Full output truncated (36 lines hidden), use '-vv' to show.all
tests/test_rotate.py:52: AssertionError
_____________________________ test_rotation[True] ______________________________
    def test_rotation():
        # Create 6 faces of a cube
        data = numpy.zeros(6, dtype=Mesh.dtype)

        # Top of the cube
        data['vectors'][0] = numpy.array([[0, 1, 1],
                                          [1, 0, 1],
                                          [0, 0, 1]])
        data['vectors'][1] = numpy.array([[1, 0, 1],
                                          [0, 1, 1],
                                          [1, 1, 1]])
        # Right face
        data['vectors'][2] = numpy.array([[1, 0, 0],
                                          [1, 0, 1],
                                          [1, 1, 0]])
        data['vectors'][3] = numpy.array([[1, 1, 1],
                                          [1, 0, 1],
                                          [1, 1, 0]])
        # Left face
        data['vectors'][4] = numpy.array([[0, 0, 0],
                                          [1, 0, 0],
                                          [1, 0, 1]])
        data['vectors'][5] = numpy.array([[0, 0, 0],
                                          [0, 0, 1],
                                          [1, 0, 1]])

        mesh = Mesh(data, remove_empty_areas=False)

        # Since the cube faces are from 0 to 1 we can move it to the middle by
        # substracting .5
        data['vectors'] -= .5

        # Rotate 90 degrees over the X axis followed by the Y axis followed by the
        # X axis
        mesh.rotate([0.5, 0.0, 0.0], math.radians(90))
        mesh.rotate([0.0, 0.5, 0.0], math.radians(90))
        mesh.rotate([0.5, 0.0, 0.0], math.radians(90))

        # Since the cube faces are from 0 to 1 we can move it to the middle by
        # substracting .5
        data['vectors'] += .5

>       assert (mesh.vectors == numpy.array([
            [[1, 0, 0], [0, 1, 0], [0, 0, 0]],
            [[0, 1, 0], [1, 0, 0], [1, 1, 0]],
            [[0, 1, 1], [0, 1, 0], [1, 1, 1]],
            [[1, 1, 0], [0, 1, 0], [1, 1, 1]],
            [[0, 0, 1], [0, 1, 1], [0, 1, 0]],
            [[0, 0, 1], [0, 0, 0], [0, 1, 0]],
        ])).all()
E       AssertionError: assert False
E        +  where False = <built-in method all of numpy.ndarray object at 0x7fff88945350>()
E        +    where <built-in method all of numpy.ndarray object at 0x7fff88945350> = array([[[9.99...dtype=float32) == array([[[1, 0,...  [0, 1, 0]]])
E             Full diff:
E             - array([[[9.9999994e-01, 2.9802322e-08, 0.0000000e+00],
E             -         [2.9802322e-08, 1.0000000e+00, 5.9604645e-08],
E             -         [0.0000000e+00, 5.9604645e-08, 2.9802322e-08]],
E             + array([[[1, 0, 0],
E             +         [0, 1, 0],
E             +         [0, 0, 0]],...
E             
E             ...Full output truncated (36 lines hidden), use '-vv' to show.all
tests/test_rotate.py:52: AssertionError
================ 2 failed, 66 passed, 2 skipped in 1.18 seconds ================

I'll try to see at what point the result is wrong.

hroncok commented 6 years ago

mesh.vectors when created:

 [[[0. 1. 1.]
  [1. 0. 1.]
  [0. 0. 1.]]
 [[1. 0. 1.]
  [0. 1. 1.]
  [1. 1. 1.]]
 [[1. 0. 0.]
  [1. 0. 1.]
  [1. 1. 0.]]
 [[1. 1. 1.]
  [1. 0. 1.]
  [1. 1. 0.]]
 [[0. 0. 0.]
  [1. 0. 0.]
  [1. 0. 1.]]
 [[0. 0. 0.]
  [0. 0. 1.]
  [1. 0. 1.]]]

mesh.vectors after -= .5:

 [[[-0.5  0.5  0.5]
  [ 0.5 -0.5  0.5]
  [-0.5 -0.5  0.5]]
 [[ 0.5 -0.5  0.5]
  [-0.5  0.5  0.5]
  [ 0.5  0.5  0.5]]
 [[ 0.5 -0.5 -0.5]
  [ 0.5 -0.5  0.5]
  [ 0.5  0.5 -0.5]]
 [[ 0.5  0.5  0.5]
  [ 0.5 -0.5  0.5]
  [ 0.5  0.5 -0.5]]
 [[-0.5 -0.5 -0.5]
  [ 0.5 -0.5 -0.5]
  [ 0.5 -0.5  0.5]]
 [[-0.5 -0.5 -0.5]
  [-0.5 -0.5  0.5]
  [ 0.5 -0.5  0.5]]]

mesh.vectors after 1st rotate:

 [[[-0.5         0.5        -0.49999997]
  [ 0.5         0.49999997  0.5       ]
  [-0.5         0.49999997  0.5       ]]
 [[ 0.5         0.49999997  0.5       ]
  [-0.5         0.5        -0.49999997]
  [ 0.5         0.5        -0.49999997]]
 [[ 0.5        -0.5         0.49999997]
  [ 0.5         0.49999997  0.5       ]
  [ 0.5        -0.49999997 -0.5       ]]
 [[ 0.5         0.5        -0.49999997]
  [ 0.5         0.49999997  0.5       ]
  [ 0.5        -0.49999997 -0.5       ]]
 [[-0.5        -0.5         0.49999997]
  [ 0.5        -0.5         0.49999997]
  [ 0.5         0.49999997  0.5       ]]
 [[-0.5        -0.5         0.49999997]
  [-0.5         0.49999997  0.5       ]
  [ 0.5         0.49999997  0.5       ]]]

mesh.vectors after 2nd rotate:

 [[[ 0.49999994  0.5        -0.5       ]
  [-0.49999997  0.49999997  0.5       ]
  [-0.5         0.49999997 -0.49999997]]
 [[-0.49999997  0.49999997  0.5       ]
  [ 0.49999994  0.5        -0.5       ]
  [ 0.49999997  0.5         0.49999997]]
 [[-0.49999994 -0.5         0.5       ]
  [-0.49999997  0.49999997  0.5       ]
  [ 0.5        -0.49999997  0.49999997]]
 [[ 0.49999997  0.5         0.49999997]
  [-0.49999997  0.49999997  0.5       ]
  [ 0.5        -0.49999997  0.49999997]]
 [[-0.49999997 -0.5        -0.49999997]
  [-0.49999994 -0.5         0.5       ]
  [-0.49999997  0.49999997  0.5       ]]
 [[-0.49999997 -0.5        -0.49999997]
  [-0.5         0.49999997 -0.49999997]
  [-0.49999997  0.49999997  0.5       ]]]

mesh.vectors after 3rd rotate:

 [[[ 0.49999994 -0.49999997 -0.5       ]
  [-0.49999997  0.5        -0.49999994]
  [-0.5        -0.49999994 -0.49999997]]
 [[-0.49999997  0.5        -0.49999994]
  [ 0.49999994 -0.49999997 -0.5       ]
  [ 0.49999997  0.49999997 -0.49999997]]
 [[-0.49999994  0.49999997  0.5       ]
  [-0.49999997  0.5        -0.49999994]
  [ 0.5         0.49999994  0.49999997]]
 [[ 0.49999997  0.49999997 -0.49999997]
  [-0.49999997  0.5        -0.49999994]
  [ 0.5         0.49999994  0.49999997]]
 [[-0.49999997 -0.49999997  0.49999997]
  [-0.49999994  0.49999997  0.5       ]
  [-0.49999997  0.5        -0.49999994]]
 [[-0.49999997 -0.49999997  0.49999997]
  [-0.5        -0.49999994 -0.49999997]
  [-0.49999997  0.5        -0.49999994]]]

mesh.vectors after += .5:

 [[[9.9999994e-01 2.9802322e-08 0.0000000e+00]
  [2.9802322e-08 1.0000000e+00 5.9604645e-08]
  [0.0000000e+00 5.9604645e-08 2.9802322e-08]]
 [[2.9802322e-08 1.0000000e+00 5.9604645e-08]
  [9.9999994e-01 2.9802322e-08 0.0000000e+00]
  [1.0000000e+00 1.0000000e+00 2.9802322e-08]]
 [[5.9604645e-08 1.0000000e+00 1.0000000e+00]
  [2.9802322e-08 1.0000000e+00 5.9604645e-08]
  [1.0000000e+00 9.9999994e-01 1.0000000e+00]]
 [[1.0000000e+00 1.0000000e+00 2.9802322e-08]
  [2.9802322e-08 1.0000000e+00 5.9604645e-08]
  [1.0000000e+00 9.9999994e-01 1.0000000e+00]]
 [[2.9802322e-08 2.9802322e-08 1.0000000e+00]
  [5.9604645e-08 1.0000000e+00 1.0000000e+00]
  [2.9802322e-08 1.0000000e+00 5.9604645e-08]]
 [[2.9802322e-08 2.9802322e-08 1.0000000e+00]
  [0.0000000e+00 5.9604645e-08 2.9802322e-08]
  [2.9802322e-08 1.0000000e+00 5.9604645e-08]]]
wolph commented 6 years ago

Well... I wouldn't really call it broken, this is simply the result of floating point inaccuracy. The test is just a bit too strict and doesn't account for floating point inaccuracies.

Apparently the ppc64le platform uses a slightly different floating point implementation within numpy. It might be related to this: https://github.com/numpy/numpy/issues/10281

Since I don't have access to a ppc64le machine I can't easily fix this (or at least, not test it) but something like this might do the trick:

assert (mesh.vectors - numpy.array([
    [[1, 0, 0], [0, 1, 0], [0, 0, 0]],
    [[0, 1, 0], [1, 0, 0], [1, 1, 0]],
    [[0, 1, 1], [0, 1, 0], [1, 1, 1]],
    [[1, 1, 0], [0, 1, 0], [1, 1, 1]],
    [[0, 0, 1], [0, 1, 1], [0, 1, 0]],
    [[0, 0, 1], [0, 0, 0], [0, 1, 0]],
])).sum() < 0.0001
hroncok commented 6 years ago

I'm playing with numpy.isclose to check if the result is close :)

wolph commented 6 years ago

Didn't know of the existence of numpy.isclose but that would be a great solution for all tests I think :)

Uvar commented 6 years ago

numpy.allclose is another option

hroncok commented 6 years ago

numpy.allclose(a, b, atol=1e-07) seems to do the job, will prep a PR

hroncok commented 6 years ago

https://github.com/WoLpH/numpy-stl/pull/79

hroncok commented 6 years ago

@WoLpH, @Uvar: Thank you both!