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

I’m trying to accomplish something that I don’t even have the correct wording for.
(If you have a better Idea, I’d be happy to rename this thread so it could maybe help someone in the future)

I have two 1d matrices, binary, either 0 or 1 (yeah, that’s pretty much what binary means :D)

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:

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] -> 1 
# [0, 1] -> 0
# [0, 0] -> the last value

# It's assumed either a or b while not be 0 at first position
# It's also assumed a==1 & b==1 will never occur

To try and be even clearer, here’s what it would look like with Python lists and iterations:
(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)

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:
    if a_value==0 and b_value==1:
    if a_value==0 and b_value==0:

I hope it’s clear.
Thanks a lot in advance,

What would be the output value, if the first position contains a zero for a and b?
This code should work:

a = torch.tensor([1, 0, 0, 0, 1, 0])
b = torch.tensor([0, 0, 1, 0, 0, 0])

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

> tensor([1, 1, 0, 0, 1, 1])

Although, is should write a 1 at the last position, if the first entry is a double 0.

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.


a = torch.tensor([1, 0, 0, 0, 0, 0, 0, 1, 0])
b = torch.tensor([0, 0, 0, 0, 0, 1, 0, 0, 0])

would result in

> tensor(1, 1, 1, 1, 1, 0, 0, 1, 1)

To answer your first question, it’s assumed either a or b will equal 1 in first pos.

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.

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).

My agent (for the part I’m currently struggling to solve anyway) can decide to put ON of OFF a state. Matrix a represents the neuron “turn it on”, and b “turn it off”.

The resulting matrix should be the resulting state.

As following operations is fairly straightforward (Matrix multiplication, error function, gradient descent), doing that one in few GPU operations would be a tremendous win.

Hence, another way to express illustratively what I’d like to achieve:

#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])
> is_walking tensor([1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1])

I’m getting back to the project where I needed that.
I’m quite certain there is a way to be found.

That post is a mere up, though only in order to not waste time in what I’m going to explain next, in case someone has an answer.

My intelligence has limits (obviously), and the answer to that problem either doesn’t exist, or lies beyond those limits.

What I’m going to try, is genetic programming. The problem seems simple enough to formulate for that approach to be somehow valid.

If I succeed I’ll both post the answer and the code used to evolve algos.

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:

nmissed += missing[t]
nmissed *= missing[t]

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.

Well genetic programming is fun anyway…