# array_correspondence

## `array_correspondence(A, B, axis=None)`

Computes a map from A to the equal elements in B

Parameters:

Name Type Description Default
`A` `(a,) or (a,k) numpy array (must be 1-dim or 2-dim)` required
`B` `(b,) or (b,k) numpy array (must be 1-dim or 2-dim)` required
`axis` `int or None, optional (default None)`

If None, will treat A and B as flat arrays. If a number, will check for equality of the entire axis, in which case the dimension of A and B across that axis must be equal.

`None`

Returns:

Name Type Description
`f` `(a,) numpy int array`

index list mapping from A to B, with -1 if there is no matching entry. If b contains multiple eligible entries, return an arbitrary one. If there are no -1s, `b[f] == a`

Examples:

TODO

Source code in `src/gpytoolbox/array_correspondence.py`
 ``` 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82``` ``````def array_correspondence(A,B,axis=None): """Computes a map from A to the equal elements in B Parameters ---------- A : (a,) or (a,k) numpy array (must be 1-dim or 2-dim) B : (b,) or (b,k) numpy array (must be 1-dim or 2-dim) axis : int or None, optional (default None) If None, will treat A and B as flat arrays. If a number, will check for equality of the entire axis, in which case the dimension of A and B across that axis must be equal. Returns ------- f : (a,) numpy int array index list mapping from A to B, with -1 if there is no matching entry. If b contains multiple eligible entries, return an arbitrary one. If there are no -1s, `b[f] == a` Examples -------- TODO """ if axis is None: A = A.ravel() B = B.ravel() # Slow for loop # f = np.full(A.size, -1, dtype=np.int64) # for a in range(A.size): # for b in range(B.size): # if A[a]==B[b]: # f[a] = b # While we have to keep track of duplicates in A (to map them to the # correct place), we do not care about duplicates in B uB,mapB = np.unique(B, return_index=True) _,idx,inv = np.unique(np.concatenate((uB,A)), return_index=True, return_inverse=True) imap = idx[inv[uB.size:]] imap[imap>=uB.size] = -1 f = np.where(imap<0, -1, mapB[imap]) else: assert len(A.shape) == 2 assert len(B.shape) == 2 assert axis==-2 or axis==-1 or axis==0 or axis==1 assert A.shape[axis] == B.shape[axis] # This function compares rows, so we reduce the problem to rows here. if axis==-2 or axis==0: A = A.transpose() B = B.transpose() # # https://stackoverflow.com/a/64930992 is too memory-intensive # inds = (A[None,:,:] == B[:,None,:]) # i,j = np.nonzero(inds.sum(axis=2) == A.shape[1]) # f = np.full(A.shape[0], -1, dtype=np.int64) # f[j] = i # # Slower (but less memory-intensive) with for loops # f = np.full(A.shape[0], -1, dtype=np.int64) # for a in range(A.shape[0]): # for b in range(B.shape[0]): # if (A[a,:]==B[b,:]).all(): # f[a] = b # Convert each row to bytes, intersect byte arrays in 1d def to_byte_array(x): # Adapted from https://stackoverflow.com/a/54683422 dt = np.dtype('S{:d}'.format(x.shape[1] * x.dtype.itemsize)) return np.frombuffer(x.tobytes(), dtype=dt) bytesA = to_byte_array(A) bytesB = to_byte_array(B.astype(A.dtype)) f = array_correspondence(bytesA,bytesB,axis=None) return f ``````