Home > Software engineering >  How to allow sign difference of any column in a comparison of two matrices, Python3?
How to allow sign difference of any column in a comparison of two matrices, Python3?

Time:09-06

I have two numpy 3d arrays with dimension of m-n-n: arr1 and arr2. Each inner array is a square matrix (n-n). In my unittest work, arr1 and arr2 should be the same, except that any column in any inner matrix in arr1 can have a different sign than that in arr2. I want to mimic the function numpy.testing.assert_almost_equal(arr1, arr2). It should output True even if there are some columns have different sign. Could you please show me how to realize it? Thanks in advance!

Here is an example below. In the 1st inner matrix, the 2nd column has a different sign; in the 2nd inner matrix, the 3rd column has a different sign; and the 3rd inner matrix has the same sign. Note that, the different sign is applied to a whole column, not a part of it.

import numpy as np

arr1 = np.array([
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]
    ],
    [
        [10, 20, 30],
        [40, 50, 60],
        [70, 80, 90]
    ],
    [
        [100, 200, 300],
        [400, 500, 600],
        [700, 800, 900]
    ]
])

arr2 = np.array([
    [
        [1, -2, 3],
        [4, -5, 6],
        [7, -8, 9]
    ],
    [
        [10, 20, -30],
        [40, 50, -60],
        [70, 80, -90]
    ],
    [
        [100, 200, 300],
        [400, 500, 600],
        [700, 800, 900]
    ]
])

np.testing.assert_almost_equal(arr1, arr2)  # How to re-write it so that the comparison results is `True`?

CodePudding user response:

is_diff_signs = ((np.sign(arr1) * np.sign(arr2)) == -1).all(axis=1, keepdims=True)

real_total    = arr1   arr2
ideal_total   = np.where(is_diff_signs, 0, real_total)

np.testing.assert_almost_equal(real_total, ideal_total)

If two arrays are equal except for full-signs for some columns, then their sums should be the "normal" sum when signs agree, and 0 otherwise.

So we first form a mask saying "whether each column pairs of arrays share the opposite signs in all entries, or not"; then select the desired sum as 0 when that's the case, and normal sum otherwise.

Here's the mask (it's of shape (3, 1, 3) (via keepdims) so that np.where broadcasts as desired):

In [173]: is_diff_signs
Out[173]:
array([[[False,  True, False]],

       [[False, False,  True]],

       [[False, False, False]]])

This says "1st inner array's 2nd column, and 2nd inner array's 3rd column differ in sign fully".

CodePudding user response:

Similar to @Mustafa's approach but using only the sign of the first row (arbitrarily) of each array and broadcasting (which is simpler in my opinion).

As we want to assert full equality, one row is sufficient to test whether the full columns match.

np.testing.assert_almost_equal(arr1 * np.sign(arr2[:,[0]]) * np.sign(arr1[:,[0]]), arr2)
# no error
  • Related