(nx)
| 1015 | @pytest.skip_backend("jax") |
| 1016 | @pytest.skip_backend("tf") |
| 1017 | def test_sinkhorn_lpl1_vectorization(nx): |
| 1018 | n_samples, n_labels = 150, 3 |
| 1019 | rng = np.random.RandomState(42) |
| 1020 | M = rng.rand(n_samples, n_samples) |
| 1021 | labels_a = rng.randint(n_labels, size=(n_samples,)) |
| 1022 | M, labels_a = nx.from_numpy(M), nx.from_numpy(labels_a) |
| 1023 | |
| 1024 | # hard-coded params from the original code |
| 1025 | p, epsilon = 0.5, 1e-3 |
| 1026 | T = nx.from_numpy(rng.rand(n_samples, n_samples)) |
| 1027 | |
| 1028 | def unvectorized(transp): |
| 1029 | indices_labels = [] |
| 1030 | classes = nx.unique(labels_a) |
| 1031 | for c in classes: |
| 1032 | (idxc,) = nx.where(labels_a == c) |
| 1033 | indices_labels.append(idxc) |
| 1034 | W = nx.ones(M.shape, type_as=M) |
| 1035 | for i, c in enumerate(classes): |
| 1036 | majs = nx.sum(transp[indices_labels[i]], axis=0) |
| 1037 | majs = p * ((majs + epsilon) ** (p - 1)) |
| 1038 | W[indices_labels[i]] = majs |
| 1039 | return W |
| 1040 | |
| 1041 | def vectorized(transp): |
| 1042 | labels_u, labels_idx = nx.unique(labels_a, return_inverse=True) |
| 1043 | n_labels = labels_u.shape[0] |
| 1044 | unroll_labels_idx = nx.eye(n_labels, type_as=transp)[labels_idx] |
| 1045 | W = ( |
| 1046 | nx.repeat(transp.T[:, :, None], n_labels, axis=2) |
| 1047 | * unroll_labels_idx[None, :, :] |
| 1048 | ) |
| 1049 | W = nx.sum(W, axis=1) |
| 1050 | W = p * ((W + epsilon) ** (p - 1)) |
| 1051 | W = nx.dot(W, unroll_labels_idx.T) |
| 1052 | return W.T |
| 1053 | |
| 1054 | assert np.allclose(unvectorized(T), vectorized(T)) |
nothing calls this directly
no test coverage detected