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

2.4.1: test_rotation fails on ppc64le #78

Closed
hroncok opened this issue May 11, 2018 · 8 comments · Fixed by #79
Closed

2.4.1: test_rotation fails on ppc64le #78

hroncok opened this issue May 11, 2018 · 8 comments · Fixed by #79

Comments

@hroncok
Copy link
Contributor

hroncok commented May 11, 2018

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
Copy link
Contributor Author

hroncok commented May 11, 2018

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
Copy link
Owner

wolph commented May 11, 2018

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: numpy/numpy#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
Copy link
Contributor Author

hroncok commented May 11, 2018

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

@wolph
Copy link
Owner

wolph commented May 11, 2018

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

@Uvar
Copy link
Collaborator

Uvar commented May 11, 2018

numpy.allclose is another option

@hroncok
Copy link
Contributor Author

hroncok commented May 11, 2018

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

hroncok added a commit to hroncok/numpy-stl that referenced this issue May 11, 2018
On some platforms, a regular (a == b).all() might not work doe to
float32 not being very precise. In one particular case, also lower
the tolerance for allclose, because on ppc64le 3 rotations are
enough to divert too much from the mathematically correct result.

We cannot increase the precision, because STL has 32bit floats.

Fixes wolph#78
hroncok added a commit to hroncok/numpy-stl that referenced this issue May 11, 2018
On some platforms, a regular (a == b).all() might not work due to
float32 not being very precise. In one particular case, also lower
the tolerance for allclose, because on ppc64le 3 rotations are
enough to divert too much from the mathematically correct result.

We cannot increase the precision, because STL has 32bit floats.

Fixes wolph#78
hroncok added a commit to hroncok/numpy-stl that referenced this issue May 11, 2018
On some platforms, a regular (a == b).all() might not work due to
float32 not being very precise. In one particular case, we also
increase the tolerance for allclose(), because on ppc64le 3
rotations are enough to divert too much from the mathematically
correct result.

We cannot increase the precision, because STL has 32bit floats.

Fixes wolph#78
@hroncok
Copy link
Contributor Author

hroncok commented May 11, 2018

#79

@wolph wolph closed this as completed in #79 May 11, 2018
@hroncok
Copy link
Contributor Author

hroncok commented May 11, 2018

@wolph, @Uvar: Thank you both!

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 a pull request may close this issue.

3 participants