Sticky cumsum/cumprod, combine two binary matrices into one with "triggers"

PotatoeHacker: <p>I’m trying to accomplish something that I don’t even have the correct wording for.<br>
(If you have a better Idea, I’d be happy to rename this thread so it could maybe help someone in the future)</p>
<p>I have two 1d matrices, binary, either 0 or 1 (yeah, that’s pretty much what binary means :D)</p>
<p>The way I framed to problem I’m trying to solve, (of which details would be of little interest here) I want the resulting matrix to be the resulting state of the two input matrices would act as “triggers”. Which I feel is totally unclear, so I’ll illustrate with an example:</p>
<pre><code class="lang-python">a = [1, 0, 0, 0, 1, 0] # Obviously not Python lists, I just want to illustrate what I'd functionnaly want
b = [0, 0, 1, 0, 0, 0]

# What I want:
result = [1, 1, 0, 0, 1, 1]

# So   where a==1 and b ==0, result should be 1
#      where a==0 and b ==1, result should be 0
#      where a==0 and b==0,  result should be the last state triggered
# [1, 0] -&gt; 1 
# [0, 1] -&gt; 0
# [0, 0] -&gt; the last value

# It's assumed either a or b while not be 0 at first position
# It's also assumed a==1 &amp; b==1 will never occur
</code></pre>
<p>To try and be even clearer, here’s what it would look like with Python lists and iterations:<br>
(Which, again, is obviously a mere illustration of what I want, if you landed here from google, that’s a scrappy and only illustrative implementation of what I functionality want)</p>
<pre><code class="lang-python">a = [1, 0, 0, 0, 1, 0] 
b = [0, 0, 1, 0, 0, 0]
results = []

for a_value, b_value in zip(a, b):
    if a_value==1 and b_value==0:
        result.append(1)
    if a_value==0 and b_value==1:
        result.append(0)
    if a_value==0 and b_value==0:
        result.append(result[-1])
</code></pre>
<p>I hope it’s clear.<br>
Thanks a lot in advance,</p>

ptrblck: <p>What would be the output value, if the first position contains a zero for <code>a</code> and <code>b</code>?<br>
This code should work:</p>
<pre><code class="lang-python">a = torch.tensor([1, 0, 0, 0, 1, 0])
b = torch.tensor([0, 0, 1, 0, 0, 0])

res = ((a==1) &amp; (b==0)).long()
idx = ((a==0) &amp; (b==0)).nonzero()
res[idx] = res[idx-1]

print(res)
&gt; tensor([1, 1, 0, 0, 1, 1])
</code></pre>
<p>Although, is should write a <code>1</code> at the last position, if the first entry is a double 0.</p>

PotatoeHacker: <aside class="quote no-group" data-username="ptrblck" data-post="2" data-topic="74783">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>a = torch.tensor([1, 0, 0, 0, 1, 0]) b = torch.tensor([0, 0, 1, 0, 0, 0]) res = ((a==1) &amp; (b==0)).long() idx = ((a==0) &amp; (b==0)).nonzero() res[idx] = res[idx-1] print(res) &gt; tensor([1, 1, 0, 0, 1, 1])</p>
</blockquote>
</aside>
<p>Thanks a lot for your answer. I knew I had to be somehow unclear on my intentions :). My problem is that I want the “equal to previous value” mechanism to be recursive.</p>
<p>Hence</p>
<pre data-code-wrap="python"><code class="lang-python">a = torch.tensor([1, 0, 0, 0, 0, 0, 0, 1, 0])
b = torch.tensor([0, 0, 0, 0, 0, 1, 0, 0, 0])
</code></pre>
<p>would result in</p>
<pre><code class="lang-auto">&gt; tensor(1, 1, 1, 1, 1, 0, 0, 1, 1)
</code></pre>
<p>To answer your first question, it’s assumed either a or b will equal 1 in first pos.</p>

PotatoeHacker: <p>I realize I choose to go that way because it would fit the way I want to frame my problem, yet I could have asked help broadening a bit the explanation about that.</p>
<p>So, I’m kind of dealing with reinforcement learning (“Kind of” because my challenge is to use as much shortcuts as possible, so no fancy Markovian formalism).</p>
<p>My agent (for the part I’m currently struggling to solve anyway) can decide to put ON of OFF a state. Matrix <code>a</code> represents the neuron “turn it on”, and <code>b</code> “turn it off”.</p>
<p>The resulting matrix should be the resulting state.</p>
<p>As following operations is fairly straightforward (Matrix multiplication, error function, gradient descent), doing that one in few GPU operations would be a tremendous win.</p>
<p>Edit:<br>
Hence, another way to express illustratively what I’d like to achieve:</p>
<pre><code class="lang-python">#I want to turn:
start_walking = torch.tensor([1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0])
stop_walking = torch.tensor([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0])
#Into
&gt; is_walking tensor([1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1])
</code></pre>

PotatoeHacker: <p>I’m getting back to the project where I needed that.<br>
I’m quite certain there is a way to be found.</p>
<p>That post is a mere <strong>up</strong>, though only in order to not waste time in what I’m going to explain next, in case someone has an answer.</p>
<p>My intelligence has limits (obviously), and the answer to that problem either doesn’t exist, or lies beyond those limits.</p>
<p>What I’m going to try, is genetic programming. The problem seems simple enough to formulate for that approach to be somehow valid.</p>
<p>If I succeed I’ll both post the answer and the code used to evolve algos.</p>

googlebot: <p>I had vaguely similar problem (last known value repeater), my conclusion was that it is not possible to do without a loop; basically you need to shift values by varying distances (still possible with gather()), and you may need to consult an arbitrary number of past values to find these distances - so not O(1) without some forward accumulator. Unfortunately, cumsum/cumprod seem inappropriate, simplest step I found was:</p>
<pre><code class="lang-auto">nmissed += missing[t]
nmissed *= missing[t]
</code></pre>

PotatoeHacker: <p>Pretty sure you’re totally right. That was my intuition though I haven’t figured any argument about what might be the minimal complexity here.</p>
<p>Well genetic programming is fun anyway…</p>