Graphegon / pygraphblas

GraphBLAS for Python
https://graphegon.github.io/pygraphblas/pygraphblas/index.html
Apache License 2.0
343 stars 27 forks source link

Meaning of matrix operation A == B #26

Closed marci543 closed 4 years ago

marci543 commented 4 years ago

I was wondering about the meaning of matrix operation A == B. Based on this code I thought it can be used to compare whether two matrices are equal. https://github.com/michelp/pygraphblas/blob/ab6d8e3290d62b887b6a52142f31f29971af99c8/tests/test_matrix.py#L112-L114

The following code shows that it's not the case: it is making an element-wise comparison (only if the sizes match), then the __nonzero__ function returns true as it has a true element. Do I understand it correctly? For comparison should is use A.iseq(B) instead?

A = Matrix.from_lists(
    [0, 1],
    [1, 2],
    [8, 2],
    nrows=3, ncols=3)
A_half = A.apply(lambda val:val//2)
A_small = A[0:1, :]

print(A); print(A.to_string())
print(A_half); print(A_half.to_string())
print(A_small); print(A_small.to_string())
print()

print('A == A_half', bool(A == A_half))
print((A == A_half).to_string())
print()

print('A_half == A_small', bool(A_half == A_small))
<Matrix (3x3 : 2:INT64)>
    0 1 2
 0|   8  | 0
 1|     2| 1
 2|      | 2
    0 1 2
<Matrix (3x3 : 2:INT64)>
    0 1 2
 0|   4  | 0
 1|     1| 1
 2|      | 2
    0 1 2
<Matrix (2x3 : 2:INT64)>
    0 1 2
 0|   8  | 0
 1|     2| 1
    0 1 2

A == A_half True
    0 1 2
 0| 1 0 1| 0
 1| 1 1 0| 1
 2| 1 1 1| 2
    0 1 2

---------------------------------------------------------------------------
DimensionMismatch                         Traceback (most recent call last)
<ipython-input-50-adf43ad6d1b4> in <module>
     16 print()
     17 
---> 18 print('A_half == A_small', bool(A_half == A_small))

~/pygraphblas/matrix.py in __eq__(self, other)
    742 
    743     def __eq__(self, other):
--> 744         return self.compare(other, operator.eq, '==')
    745 
    746     def __ne__(self, other):

~/pygraphblas/matrix.py in compare(self, other, op, strop)
    724             A = self.full()
    725             B = other.full()
--> 726             A.emult(B, strop, out=C)
    727             return C
    728         else:

~/pygraphblas/matrix.py in emult(self, other, mult_op, out, **kwargs)
    405             self.matrix[0],
    406             other.matrix[0],
--> 407             desc))
    408         return out
    409 

~/pygraphblas/base.py in _check(res)
    111 def _check(res):
    112     if res != lib.GrB_SUCCESS:
--> 113         raise _error_codes[res](ffi.string(lib.GrB_error()))
    114 
    115 def _check_no_val_key_error(res):

DimensionMismatch: b'GraphBLAS error: GrB_DIMENSION_MISMATCH\nfunction: GrB_eWiseMult_Matrix_BinaryOp (C, M, accum, mult, A, B, desc)\nDimensions not compatible:\noutput is 3-by-3\nfirst input is 3-by-3\nsecond input is 2-by-3\n'
michelp commented 4 years ago

I was wondering about the meaning of matrix operation A == B. Based on this code I thought it can be used to compare whether two matrices are equal.

https://github.com/michelp/pygraphblas/blob/ab6d8e3290d62b887b6a52142f31f29971af99c8/tests/test_matrix.py#L112-L114

That test code is broken, sorry it led you astray, I'll fix it up.

The following code shows that it's not the case: it is making an element-wise comparison (only if the sizes match), then the __nonzero__ function returns true as it has a true element. Do I understand it correctly? For comparison should is use A.iseq(B) instead?

Yes. A.iseq(B) calls LAGraph_isequal() which is what you want. The behavior of A == B is meant to be identical to that of the MATLAB wrapper and I based it off of Tim's work. you're right, it does element-wise comparison and returns a dense boolean matrix. The above test you reference was from before I did that work and was more confused about it.

marci543 commented 4 years ago

Thanks for the detailed explanation. I removed those two lines in #27.