Index adding over multiple dimensions

lapertor: <p>Is there a way to use <code>index_add</code> with the <code>index</code> argument being more that 1-dimensional ?<br>
More especially, if I have a 2d-array that I want to fill not row by row or column by column, but element by element by specifying the 2d coordinates in which to add the desired amount in the 2d-array.</p>
<p>Example:</p>
<pre><code class="lang-auto">&gt;&gt;&gt; to_be_filled = torch.zeros((2, 7))
&gt;&gt;&gt; to_be_filled
torch.tensor([
    [0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0]
])
&gt;&gt;&gt; index = torch.tensor([
    [0, 1], # adding 0.4
    [0, 2], # adding -1.4
    [0, 3], # adding -1.13
    [0, 6], # adding -1
    [1, 2], # adding 3
    [0, 1]  # adding 2
])
&gt;&gt;&gt; values = torch.tensor([
    0.4,    # at coordinates (0, 1)
    -1.4,   # at coordinates (0, 2)
    -1.13,  # at coordinates (0, 3)
    -1,     # at coordinates (0, 6)
    3,      # at coordinates (1, 2)
    2       # at coordinates (0, 1)
])
</code></pre>
<p>I would like to do this like the following, but I have an error:</p>
<pre><code class="lang-auto">&gt;&gt;&gt; to_be_filled.index_add_(0, index, values)
IndexError: index_add_(): Index is supposed to be a vector
</code></pre>
<p>Expected result:</p>
<pre><code class="lang-auto">torch.tensor([
    [0, 2.4, -1.4, -1.13, 0, 0, -1], 
    [0, 0, 3, 0, 0, 0, 0]
])
</code></pre>
<p>Is there a way to do this using pytorch operations?</p>
<p><em>Note:</em> doing <code>to_be_filled[index[:, 0], index[:, 1]] += values</code> yields the following result:</p>
<pre><code class="lang-auto">torch.tensor([
    [0, 2, -1.4, -1.13, 0, 0, -1], 
    [0, 0, 3, 0, 0, 0, 0]
])
</code></pre>
<p>This approach does not accumulate when an index appear twice or more (notice that <code>to_be_filled[0, 1] == 2</code> instead of <code>2.4</code>)</p>

vainaijr: <p>but why would you not directly specify 2.4 to add, instead of 0.4, and then 2, that is accumulate the same coordinates values in the values tensor itself</p>
<p>another way to do this is through,</p>
<pre><code class="lang-auto">values = torch.tensor([
    [0.4],    # at coordinates (0, 1)
    [-1.4],   # at coordinates (0, 2)
    [-1.13],  # at coordinates (0, 3)
    [-1],     # at coordinates (0, 6)
    [3],      # at coordinates (1, 2)
    [2]       # at coordinates (0, 1)
])
to_be_filled[index.split(1, 1)] += values
</code></pre>
<p>but it would also consider the last addition for each index, and give 2, not 2.4</p>

lapertor: <p>Firstly, thanks for the answer!</p>
<p>As of why I would not directly specify the sum for each index, is because I have no choice: my data have this shape, with some indexes appearing twice or more, and I have to work with it. I don’t decide of the shape of it, it comes like that.</p>
<p>Grouping by index and summing as you say would also answer my needs (like a <code>groupby</code> operation on a <code>pandas.DataFrame</code> and then aggregate with a sum, and then doing <code>to_be_filled[index[:, 0], index[:, 1]] += values</code> or <code>to_be_filled[index.split(1, 1)] += values</code> as you said), but I am convinced that there is a way to do it the way I said. I just find to find how.</p>

KFrank: <p>Hi Lapertor!</p>
<aside class="quote no-group quote-modified" data-username="lapertor" data-post="3" data-topic="124709" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/lapertor/48/39534_2.png" class="avatar"> lapertor:</div>
<blockquote>
<p>Grouping by index and summing as you say would also answer my needs<br>
…<br>
but I am convinced that there is a way to do it the way I said.</p>
</blockquote>
</aside>
<p>If by “the way I said” means to perform your computation with a single<br>
pytorch tensor operation <em>in the presence of duplicate indices,</em> then I<br>
don’t think it’s possible.</p>
<p>It’s difficult to prove a negative, but I think any kind of pytorch "advanced<br>
indexing* or <code>index_add</code>-style approach will give the “wrong” answer<br>
(and potentially become non-deterministic) when confronted with<br>
duplicate indices.</p>
<p>My assumption is that pytorch, for efficiency reasons, does the indexed<br>
operation, figuratively speaking, “in parallel,” breaking the semantics<br>
you would expect if you had coded the operation with sequential loops.</p>
<p>In my experience, as with Vainaijr’s observation, “the last addition for<br>
each index, and give 2, not 2.4,” the behavior is as if the result for just<br>
one of a set duplicate indices overwrites the others.  Furthermore, I<br>
believe that pytorch makes no guarantee as to which index “wins” so<br>
that your result may change if you move your computation to the gpu<br>
or change the size of your tensors, etc.</p>
<p>I would be very interested to hear if you do find a way to perform such<br>
indexed operations in the presence of duplicate indices.  (It would be<br>
great if an expert would weigh in on this.)</p>
<p>Best.</p>
<p>K. Frank</p>

lapertor: <p>Thanks for the answer K. Frank!</p>
<aside class="quote no-group" data-username="KFrank" data-post="4" data-topic="124709">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/k/ecb155/48.png" class="avatar"> KFrank:</div>
<blockquote>
<p>If by “the way I said” means to perform your computation with a single<br>
pytorch tensor operation <em>in the presence of duplicate indices</em></p>
</blockquote>
</aside>
<p>This is indeed what I mean</p>
<aside class="quote no-group" data-username="KFrank" data-post="4" data-topic="124709">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/k/ecb155/48.png" class="avatar"> KFrank:</div>
<blockquote>
<p>In my experience, as with Vainaijr’s observation, “the last addition for<br>
each index, and give 2, not 2.4,” the behavior is as if the result for just<br>
one of a set duplicate indices overwrites the others. Furthermore, I<br>
believe that pytorch makes no guarantee as to which index “wins” so<br>
that your result may change if you move your computation to the gpu<br>
or change the size of your tensors, etc.</p>
</blockquote>
</aside>
<p>It really feels like acting as you describe here, and the more I think about this, the more I feel like there isn’t any clean way of doing this with tensor operations.</p>
<p>I used a workaround specific to my application in order to avoid this issue for now, but I still hope that an expert sees that topic and gives insights as I think that I am not the first to encounter an issue similar to this one.</p>

ahyunSeo: <p>Hello,</p>
<p>I had a similar issue today and here’s my solution (FYI).<br>
(credit : <a href="https://stackoverflow.com/a/65584479" class="inline-onebox" rel="noopener nofollow ugc">numpy - Add a index selected tensor to another tensor with overlapping indices in pytorch - Stack Overflow</a>)</p>
<pre><code class="lang-auto">to_be_filled = torch.zeros((2, 7))
index = torch.tensor([
    [0, 1], # adding 0.4
    [0, 2], # adding -1.4
    [0, 3], # adding -1.13
    [0, 6], # adding -1
    [1, 2], # adding 3
    [0, 1]  # adding 2
])
values = torch.tensor([
    0.4,    # at coordinates (0, 1)
    -1.4,   # at coordinates (0, 2)
    -1.13,  # at coordinates (0, 3)
    -1,     # at coordinates (0, 6)
    3,      # at coordinates (1, 2)
    2       # at coordinates (0, 1)
])

filled = torch.index_put(to_be_filled, (index[:, 0], index[:, 1]), values, accumulate=True)
</code></pre>
<p>The result of ‘filled’ is</p>
<pre><code class="lang-auto">tensor([[ 0.0000,  2.4000, -1.4000, -1.1300,  0.0000,  0.0000, -1.0000],
        [ 0.0000,  0.0000,  3.0000,  0.0000,  0.0000,  0.0000,  0.0000]])
</code></pre>
<p>Best,</p>