A[np.unique(np.sort(A,1).view("int, int, int, int"), return_index=True)[1]]
In steps:
In [385]: A
Out[385]:
array([[100, 1, 500, 1],
[100, 1, 501, 1],
[101, 1, 501, 1],
[102, 2, 502, 2],
[500, 1, 100, 1],
[100, 1, 500, 1],
[502, 2, 102, 2],
[502, 1, 102, 1]])
We can eliminate the need for swapping columns 0 and 2 (the thing where A[i] = A[j, [2,1,0,3]) simply by sorting each row. We don't have to worry about swapping columns 1 and 3, since for all rows in A, we have column 1 equals column 3: A[:, 1] == A[:, 3].
In [386]: As = np.sort(A,1)
In [387]: As
Out[387]:
array([[ 1, 1, 100, 500],
[ 1, 1, 100, 501],
[ 1, 1, 101, 501],
[ 2, 2, 102, 502],
[ 1, 1, 100, 500],
[ 1, 1, 100, 500],
[ 2, 2, 102, 502],
[ 1, 1, 102, 502]])
Find the unique rows in As (the sorted array). View it as a structured array where each row is a single element (since np.unique will otherwise flatten the array first)
In [388]: As.view('int, int, int, int')
Out[388]:
array([[(1, 1, 100, 500)],
[(1, 1, 100, 501)],
[(1, 1, 101, 501)],
[(2, 2, 102, 502)],
[(1, 1, 100, 500)],
[(1, 1, 100, 500)],
[(2, 2, 102, 502)],
[(1, 1, 102, 502)]],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8')])
In [389]: u, i = np.unique(As.view('int, int, int, int'), return_index=True)
In [390]: i
Out[390]: array([0, 1, 2, 7, 3])
And use them to get the rows that were unique in As from the original array A:
In [391]: A[i]
Out[391]:
array([[100, 1, 500, 1],
[100, 1, 501, 1],
[101, 1, 501, 1],
[502, 1, 102, 1],
[102, 2, 502, 2]])