# function for normalized change in probabilities

I need a function that takes in a vector of probabilities, a value and an index. the value is can be negative, 0 or positive, and can be of any absolute value.

it then adds the value to the probability in the index given inside the vector, and re scales it to sum up to one. the output vector has to be a probability distribution - so it has to still sum up to one, and include only values between 0 to 1.

one more important feature that I need is that of I add a positive value to a probability, the resulting probability will always be higher. if I add a negative value, it will always be smaller.

examples:

func([0.1,0.2,0.3,0.4], 0.1, 3) -- > [0.1, 0.2, 0.3, 0.5]  --> something like: [0.08, 0.18, 0.28, 0.46]


so 0.4 went up, and all others went down.

func([0. ,0. ,0., 1.], 0.1, 3) -- > [0., 0., 0., 1.1]  --> [0. ,0. ,0., 1.]


since no value van be higher than 1, it stayed the same

func([0. ,0. ,0., 1.], -0.1, 3) -- > [0., 0., 0., 0.9]  --> something like: [0.02 ,0.02 ,0.02, 0.94]


here I used a negative value, so ind 3 went down.

I tried softmax, dividing by sum, dividing by (1/sum) and combinations of those, but nothing works as I need. any ideas?

I haven't checked it much, but this seems to do the trick in your example, basically I sum the value [val] in position [ind] and subtract [val] / (len(probs) -1 ) elsewhere, then take elementwise max(x, 0) and normalize

import numpy as np
def f(probs, val, ind):
probs[ind] += val
probs[mask] -= val / (len(probs) - 1)
return np.clip(probs, 0, np.infty) / np.sum(np.clip(probs, 0, np.infty))


On your example it runs as

f(np.array([0.1 ,0.2 ,0.3, 0.4]), 0.1, 3) --> array([0.06666667, 0.16666667, 0.26666667, 0.5 ])

f(np.array([0. ,0. ,0., 1.]), 0.1, 3) --> array([0., 0., 0., 1.])

f(np.array([0. ,0. ,0., 1.]), -0.1, 3) --> array([0.03333333, 0.03333333, 0.03333333, 0.9 ])

After adding the value to the probability at the given index, here's one idea for how to adjust the resulting vector (let's call it $$v'$$) to get a probability distribution that should meet the requirements.

If the value added initially was nonnegative, then just divide $$v'$$ by the sum of its entries, and stop there. (I'm assuming here that the starting vector is a probability distribution, as in the examples given in the question.)

If the value added initially was negative, we might have to get more creative since the absolute value of what was added is unrestricted. For example, if we added -10, then the given entry of $$v'$$ would definitely be negative, and so a simple multiplicative rescaling wouldn't do the trick.

Instead, we could replace the given entry of $$v'$$ by 0 if it's negative, and otherwise leave it alone. Let's call the resulting vector $$v''$$. This way, at least, all the entries of $$v''$$ are nonnegative. Then divide $$v''$$ by the sum of its entries. On the off chance that every entry of $$v''$$ is 0, so that we'd be dividing by 0, return the uniform distribution.

Edit: One tweak to the case of a negative value being added at the start can address the need for a strictly lower probability in that entry, assuming the starting probability wasn't 0. After we have $$v''$$, if all entries besides the given entry are 0, then add some arbitrary positive number to all entries. (For example 1, or the absolute value of the number that was added at the beginning.) Then proceed with dividing the vector by the sum of these shifted values. Note that this removes the need for a separate sub-case where the uniform distribution is returned.

• ty, but doesn't this idea fails on the third example I provided? – מורן רזניק Jun 29 at 7:54
• So you want a strict decrease if possible? I wasn't quite clear on that point. – Jason Jun 29 at 8:04