Update.
[pytorch.git] / eingather.py
1 #!/usr/bin/env python
2
3 # Any copyright is dedicated to the Public Domain.
4 # https://creativecommons.org/publicdomain/zero/1.0/
5
6 # Written by Francois Fleuret <francois@fleuret.org>
7
8 import re, torch
9
10 #####################
11
12
13 def eingather(op, src, *indexes):
14     s_src, s_dst = re.search("^([^ ]*) *-> *(.*)", op).groups()
15     s_indexes = re.findall("\(([^)]*)\)", s_src)
16     s_src = re.sub("\([^)]*\)", "_", s_src)
17
18     shape = tuple(src.size(s_src.index(v)) for v in s_dst)
19
20     idx = []
21     n_index = 0
22
23     for i in range(src.dim()):
24         v = s_src[i]
25         if v == "_":
26             index, s_index = indexes[n_index], s_indexes[n_index]
27             n_index += 1
28
29             sub_idx = []
30
31             for i in range(index.dim()):
32                 v = s_index[i]
33                 j = s_dst.index(v)
34                 a = (
35                     torch.arange(index.size(i))
36                     .reshape((1,) * j + (-1,) + (1,) * (len(s_dst) - j - 1))
37                     .expand(shape)
38                 )
39                 sub_idx.append(a)
40
41             index = index[sub_idx]
42             idx.append(index)
43         else:
44             j = s_dst.index(v)
45             a = (
46                 torch.arange(src.size(i))
47                 .reshape((1,) * j + (-1,) + (1,) * (len(s_dst) - j - 1))
48                 .expand(shape)
49             )
50             idx.append(a)
51
52     return src[idx]
53
54
55 #######################
56
57 src = torch.rand(3, 5, 7, 11, 13)
58 index1 = torch.randint(src.size(2), (src.size(4), src.size(1), src.size(4)))
59 index2 = torch.randint(src.size(3), (src.size(1),))
60
61 # I want result[a, c, e] = src[c, a, index1[e, a, e], index2[a], e]
62
63 result = eingather("ca(eae)(a)e -> ace", src, index1, index2)
64
65 # Check
66
67 error = 0
68
69 for a in range(result.size(0)):
70     for c in range(result.size(1)):
71         for e in range(result.size(2)):
72             error += (result[a, c, e] - src[c, a, index1[e, a, e], index2[a], e]).abs()
73
74 print(error.item())