How to fill 2D binary tensor without using for loop?

qiminchen: <p>Suppose I have a tensor <code>a</code> and I want to fill the inner with all 1 like tensor <code>b</code></p>
<pre><code class="lang-auto">print(a)
tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 1., 1., 1., 1., 0., 0., 0.],
        [0., 1., 0., 1., 1., 1., 1., 1., 0., 0.],
        [0., 1., 0., 0., 1., 0., 0., 0., 1., 0.],
        [0., 1., 0., 1., 0., 0., 0., 0., 1., 0.],
        [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.],
        [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.],
        [0., 0., 1., 0., 0., 0., 0., 1., 0., 0.],
        [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

print(b)
tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 1., 1., 1., 1., 0., 0., 0.],
        [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
        [0., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
        [0., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
        [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
        [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
        [0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
        [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
</code></pre>
<p>I’m currently using the <code>for</code> loop to do this, are there any ways to do this <strong>without</strong> using the <code>for</code> loop? Thanks.</p>
<ul>
<li>Only using Pytorch</li>
<li>The areas I want to fill always have contiguous boundaries.</li>
<li>
<code>for</code> loop below loops through <code>row</code> first then <code>column</code>
</li>
</ul>
<pre><code class="lang-auto">b = torch.zeros(a.shape)
for i in range(a.shape[0]):
    occupied = torch.where(a[i] == 1)[0]
    if len(occupied) &gt; 0:
        # indexes in occupied are in ascending order so value of any index
        # between the first and last is filled with 1
        for j in range(occupied[0], occupied[-1] + 1):
            b[i][j] = 1
</code></pre>

KFrank: <p>Hi Qimin!</p>
<aside class="quote no-group quote-modified" data-username="qiminchen" data-post="1" data-topic="169985" 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/qiminchen/48/20829_2.png" class="avatar"> qiminchen:</div>
<blockquote>
<p>are there any ways to do this <strong>without</strong> using the <code>for</code> loop?</p>
<pre><code class="lang-auto">b = torch.zeros(a.shape)
for i in range(a.shape[0]):
    occupied = torch.where(a[i] == 1)[0]
    if len(occupied) &gt; 0:
        # indexes in occupied are in ascending order so value of any index
        # between the first and last is filled with 1
        for j in range(occupied[0], occupied[-1] + 1):
            b[i][j] = 1
</code></pre>
</blockquote>
</aside>
<p>You may use <code>cumsum()</code> to mark those entries that appear to the right<br>
of a <code>1.0</code> and similarly use <code>flip()</code> with <code>cumsum()</code> to mark those entries<br>
that appear to the left of a <code>1.0</code>.  You may then use arithmetical (or logical)<br>
operations to combine those pieces together to get your final result:</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; import torch
&gt;&gt;&gt; print (torch.__version__)
1.13.0
&gt;&gt;&gt;
&gt;&gt;&gt; a = torch.tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
...                   [0., 0., 1., 1., 1., 1., 1., 0., 0., 0.],
...                   [0., 1., 0., 1., 1., 1., 1., 1., 0., 0.],
...                   [0., 1., 0., 0., 1., 0., 0., 0., 1., 0.],
...                   [0., 1., 0., 1., 0., 0., 0., 0., 1., 0.],
...                   [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.],
...                   [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.],
...                   [0., 0., 1., 0., 0., 0., 0., 1., 0., 0.],
...                   [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
...                   [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
&gt;&gt;&gt;
&gt;&gt;&gt; c = torch.tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
...                   [0., 0., 1., 1., 1., 1., 1., 0., 0., 0.],
...                   [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
...                   [0., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
...                   [0., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
...                   [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
...                   [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
...                   [0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
...                   [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
...                   [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
&gt;&gt;&gt;
&gt;&gt;&gt; # using for loop
&gt;&gt;&gt; b = torch.zeros(a.shape)
&gt;&gt;&gt; for i in range(a.shape[0]):
...     occupied = torch.where(a[i] == 1)[0]
...     if len(occupied) &gt; 0:
...         # indexes in occupied are in ascending order so value of any index
...         # between the first and last is filled with 1
...         for j in range(occupied[0], occupied[-1] + 1):
...             b[i][j] = 1
...
&gt;&gt;&gt; torch.equal (b, c)
True
&gt;&gt;&gt;
&gt;&gt;&gt; # loop-free version
&gt;&gt;&gt; aleft = a.flip (1).cumsum (1).flip (1)
&gt;&gt;&gt; aright = a.cumsum (1)
&gt;&gt;&gt; d = ((aleft * aright + a) &gt; 0).float()
&gt;&gt;&gt;
&gt;&gt;&gt; torch.equal (d, c)
True
</code></pre>
<p>Best.</p>
<p>K. Frank</p>

qiminchen: <p>This is smart! Thank you Frank</p>